line-client

LINE messaging integration via Chrome extension gateway. Send/read LINE messages, manage contacts, groups, profile, and reactions. Authenticate with QR code login. Provides HMAC-signed API access through the Chrome extension gateway (line-chrome-gw.line-apps.com).

3,891 stars

Best use case

line-client is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

LINE messaging integration via Chrome extension gateway. Send/read LINE messages, manage contacts, groups, profile, and reactions. Authenticate with QR code login. Provides HMAC-signed API access through the Chrome extension gateway (line-chrome-gw.line-apps.com).

Teams using line-client should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/line-client/SKILL.md --create-dirs "https://raw.githubusercontent.com/openclaw/skills/main/skills/2manslkh/line-client/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/line-client/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How line-client Compares

Feature / Agentline-clientStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

LINE messaging integration via Chrome extension gateway. Send/read LINE messages, manage contacts, groups, profile, and reactions. Authenticate with QR code login. Provides HMAC-signed API access through the Chrome extension gateway (line-chrome-gw.line-apps.com).

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# LINE Client Skill

Full LINE messaging client via the Chrome extension gateway JSON API.

## Repo & Files

- **Repo:** `/data/workspace/line-client` ([github.com/2manslkh/line-api](https://github.com/2manslkh/line-api))
- **Main client:** `src/chrome_client.py` → `LineChromeClient`
- **QR login:** `src/auth/qr_login.py` → `QRLogin`
- **HMAC signer:** `src/hmac/signer.js` (Node.js, auto-starts on port 18944)
- **Token storage:** `~/.line-client/tokens.json`
- **Certificate cache:** `~/.line-client/sqr_cert`
- **WASM files:** `lstm.wasm` + `lstmSandbox.js` (required, in repo root)

## Quick Start

```python
import json
from pathlib import Path
from src.chrome_client import LineChromeClient

tokens = json.loads((Path.home() / ".line-client" / "tokens.json").read_text())
client = LineChromeClient(auth_token=tokens["auth_token"])

# Send a message
client.send_message("U...", "Hello!")

# Get profile
profile = client.get_profile()
```

Tokens expire in ~7 days. If expired (`APIError(10051)`), re-run QR login.

## QR Login (Authentication)

QR login requires user interaction: scan QR on phone + enter PIN.

```python
from src.hmac import HmacSigner
from src.auth.qr_login import QRLogin
import qrcode

signer = HmacSigner(mode="server")
login = QRLogin(signer)
result = login.run(
    on_qr=lambda url: send_qr_image_to_user(qrcode.make(url)),
    on_pin=lambda pin: send_pin_to_user_IMMEDIATELY(pin),  # TIME SENSITIVE!
    on_status=lambda msg: print(msg),
)
# result.auth_token, result.mid, result.refresh_token
```

**Critical:** The PIN must reach the user within ~60 seconds. Send it the instant `on_pin` fires.

### QR Login State Machine
1. `createSession` → session ID
2. `createQrCode` → callback URL (append `?secret={curve25519_pubkey}&e2eeVersion=1`)
3. `checkQrCodeVerified` — poll until scan (uses `X-Line-Session-ID`, no `origin` header)
4. **`verifyCertificate`** — MUST be called even if it fails (required state transition!)
5. `createPinCode` → 6-digit PIN (skip if cert verified in step 4)
6. `checkPinCodeVerified` — poll until user enters PIN
7. `qrCodeLoginV2` → JWT token + certificate + refresh token

### Server-Side Login Script
```bash
python scripts/qr_login_server.py /tmp/qr.png
```
Emits JSON events on stdout: `{"event": "qr", "path": "...", "url": "..."}`, `{"event": "pin", "pin": "123456"}`, `{"event": "done", "mid": "U..."}`.

## All API Methods

### Contacts & Friends

| Method | Args | Description |
|--------|------|-------------|
| `get_profile()` | — | Get your own profile (displayName, mid, statusMessage, etc.) |
| `get_contact(mid)` | mid: str | Get a single contact's profile |
| `get_contacts(mids)` | mids: list[str] | Get multiple contacts |
| `get_all_contact_ids()` | — | List all friend MIDs |
| `find_contact_by_userid(userid)` | userid: str | Search by LINE ID |
| `find_and_add_contact_by_mid(mid)` | mid: str | Add friend by MID |
| `find_contacts_by_phone(phones)` | phones: list[str] | Search by phone numbers |
| `add_friend_by_mid(mid)` | mid: str | Add friend (RelationService) |
| `get_blocked_contact_ids()` | — | List blocked MIDs |
| `get_blocked_recommendation_ids()` | — | List blocked recommendations |
| `block_contact(mid)` | mid: str | Block a contact |
| `unblock_contact(mid)` | mid: str | Unblock a contact |
| `block_recommendation(mid)` | mid: str | Block a friend suggestion |
| `update_contact_setting(mid, flag, value)` | mid, flag: int, value: str | Update contact setting (e.g. mute) |
| `get_favorite_mids()` | — | List favorited contact MIDs |
| `get_recommendation_ids()` | — | List friend suggestions |

### Messages

| Method | Args | Description |
|--------|------|-------------|
| `send_message(to, text, ...)` | to: str, text: str, reply_to: str (opt) | Send a text message. Supports replies via `reply_to=message_id` |
| `unsend_message(message_id)` | message_id: str | Unsend/delete a sent message |
| `get_recent_messages(chat_id, count=50)` | chat_id: str | Get latest messages in a chat |
| `get_previous_messages(chat_id, end_seq, count=50)` | chat_id, end_seq: int | Paginated history (older messages) |
| `get_messages_by_ids(message_ids)` | message_ids: list[str] | Fetch specific messages |
| `get_message_boxes(count=50)` | — | Get chat list with last message (inbox view) |
| `get_message_boxes_by_ids(chat_ids)` | chat_ids: list[str] | Get specific chats with last message |
| `get_message_read_range(chat_ids)` | chat_ids: list[str] | Get read receipt info |
| `send_chat_checked(chat_id, last_message_id)` | chat_id, last_message_id: str | Mark messages as read |
| `send_chat_removed(chat_id, last_message_id)` | chat_id, last_message_id: str | Remove chat from inbox |
| `send_postback(to, postback_data)` | to, postback_data: str | Send postback (bot interactions) |

### Chats & Groups

| Method | Args | Description |
|--------|------|-------------|
| `get_chats(chat_ids, with_members=True, with_invitees=True)` | chat_ids: list[str] | Get chat/group details |
| `get_all_chat_mids()` | — | List all chat MIDs (groups + invites) |
| `create_chat(name, target_mids)` | name: str, target_mids: list[str] | Create a new group chat |
| `accept_chat_invitation(chat_id)` | chat_id: str | Accept group invite |
| `reject_chat_invitation(chat_id)` | chat_id: str | Reject group invite |
| `invite_into_chat(chat_id, mids)` | chat_id: str, mids: list[str] | Invite users to group |
| `cancel_chat_invitation(chat_id, mids)` | chat_id: str, mids: list[str] | Cancel pending invites |
| `delete_other_from_chat(chat_id, mids)` | chat_id: str, mids: list[str] | Kick members from group |
| `leave_chat(chat_id)` | chat_id: str | Leave a group chat |
| `update_chat(chat_id, updates)` | chat_id: str, updates: dict | Update group name/settings |
| `set_chat_hidden_status(chat_id, hidden)` | chat_id: str, hidden: bool | Archive/unarchive a chat |
| `get_rooms(room_ids)` | room_ids: list[str] | Get legacy room info |
| `invite_into_room(room_id, mids)` | room_id: str, mids: list[str] | Invite to legacy room |
| `leave_room(room_id)` | room_id: str | Leave legacy room |

### Reactions

| Method | Args | Description |
|--------|------|-------------|
| `react(message_id, reaction_type)` | message_id: str, type: int | React to a message. Types: 2=like, 3=love, 4=laugh, 5=surprised, 6=sad, 7=angry |
| `cancel_reaction(message_id)` | message_id: str | Remove your reaction |

### Profile & Settings

| Method | Args | Description |
|--------|------|-------------|
| `update_profile_attributes(attr, value, meta={})` | attr: int, value: str | Update profile. Attrs: 2=DISPLAY_NAME, 16=STATUS_MESSAGE, 4=PICTURE_STATUS |
| `update_status_message(message)` | message: str | Shortcut: update status message |
| `update_display_name(name)` | name: str | Shortcut: update display name |
| `get_settings()` | — | Get all account settings |
| `get_settings_attributes(attr_bitset)` | attr_bitset: int | Get specific settings |
| `update_settings_attributes(attr_bitset, settings)` | attr_bitset: int, settings: dict | Update settings |

### Polling & Events

| Method | Args | Description |
|--------|------|-------------|
| `get_last_op_revision()` | — | Get latest operation revision number |
| `fetch_ops(count=50)` | — | Fetch pending operations (may long-poll) |
| `poll()` | — | Generator yielding operations as they arrive |
| `on_message(handler)` | handler: Callable(msg, client) | Start polling thread, calls handler on new messages. Op types: 26=SEND_MESSAGE, 27=RECEIVE_MESSAGE |
| `stop()` | — | Stop the polling thread |

### Other Services

| Method | Args | Description |
|--------|------|-------------|
| `get_server_time()` | — | Get LINE server timestamp |
| `get_configurations()` | — | Get server configurations |
| `get_rsa_key_info()` | — | Get RSA key for auth |
| `issue_channel_token(channel_id)` | channel_id: str | Issue channel token (LINE Login/LIFF) |
| `get_buddy_detail(mid)` | mid: str | Get official account info |
| `report_abuse(mid, category=0, reason="")` | mid: str | Report a user |
| `add_friend_by_mid(mid)` | mid: str | Add friend (RelationService) |
| `logout()` | — | Logout and invalidate token |

## MID Format

LINE identifies entities by MID:
- `U...` or `u...` → User (toType=0)
- `C...` or `c...` → Group chat (toType=2)
- `R...` or `r...` → Room (toType=1)

The client auto-detects `toType` from the MID prefix when sending messages.

## HMAC Signing

All API calls require `X-Hmac` header. The WASM signer handles this automatically:
- Derives key from version "3.7.1" + access token via proprietary KDF (in lstm.wasm)
- Signs `path + body` → base64 → `X-Hmac`
- Server mode: ~13ms/sign (Node.js HTTP server on port 18944, auto-started)
- Subprocess mode: ~2s/sign (fallback)

## Error Handling

```python
from src.chrome_client import APIError

try:
    client.send_message(mid, "test")
except APIError as e:
    print(e.code, e.api_message)
    # 10051 = session expired / invalid
    # 10052 = HTTP error from backend
    # 10102 = invalid arguments
```

## Architecture

```
User's Phone (LINE app)
    ↕ (scan QR / enter PIN)
LINE Servers (line-chrome-gw.line-apps.com)
    ↕ (JSON REST + X-Hmac signing)
LineChromeClient (this repo)
    ↕ (WASM HMAC via Node.js signer)
lstm.wasm + lstmSandbox.js
```

The Chrome Gateway translates JSON ↔ Thrift internally. We never deal with Thrift binary — everything is clean JSON.

Related Skills

Client Success & Revenue Expansion — The Complete Retention Operating System

3891
from openclaw/skills

Turn clients into long-term revenue engines. This isn't advice — it's a complete operating system with scoring models, templates, playbooks, and automation patterns that work for any B2B or B2C subscription business.

Customer Success & Retention

outline-kb

3891
from openclaw/skills

Outline 知识库 API 交互。搜索文档、创建/编辑文档、管理 Collections、列出用户等。当用户需要与 Outline 知识库交互时使用,包括搜索内容、创建文档、查看文档结构、导出文档、管理权限等。

Workflow & Productivity

docs-pipeline-automation

3891
from openclaw/skills

Build repeatable data-to-Docs pipelines from Sheets and Drive sources. Use for automated status reports, template-based document assembly, and scheduled publishing workflows.

Workflow & Productivity

Skill: Gmail Auto-Reply for Client

3891
from openclaw/skills

## Purpose

linear-todos

3891
from openclaw/skills

A CLI tool that executes Python source code to manage todos via Linear's API. Creates tasks with natural language dates, priorities, and scheduling. This is a source-execution skill - code in src/linear_todos/ runs when commands are invoked.

pipeline-analytics

3891
from openclaw/skills

Generate interactive analytics dashboards from CRM data. Use when asked to "show pipeline stats", "create a report", "analyze leads", "show conversion rates", "build a dashboard", "visualize outreach data", "funnel analysis", or any data visualization request from DuckDB workspace data.

linear-webhook

3891
from openclaw/skills

Comment @mason or @eureka in Linear issues to dispatch tasks to agents. Webhook receives Linear comments and routes to correct agent.

client-flow

3891
from openclaw/skills

Automated client onboarding and project lifecycle management. From a single message, creates Google Drive/Dropbox project folder structure, generates project brief, sends templated welcome email, schedules kickoff meeting on Google Calendar, sets up task board in Todoist/ClickUp/Linear/Asana/Notion, configures follow-up reminders, and maintains a master client registry with status tracking. Use this skill for: new client onboarding, project setup, client intake, welcome email, kickoff meeting scheduling, project kickoff, client management, project status dashboard, "new client [name]", "onboard [company]", "set up a project for [client]", "how are my projects doing", client portfolio overview, project lifecycle tracking, client communication templates, progress update emails, project closure workflow, freelancer project management, agency client management, or any request involving setting up and tracking client projects. One message replaces 30 minutes of manual setup across email, calendar, file storage, and task management tools.

openstoryline-use

3891
from openclaw/skills

Use this skill when OpenStoryline is already installed and the user wants to start the local MCP/Web services, create or continue a session, send editing instructions, perform multi-turn re-editing, and verify rendered video outputs, as well as Chinese requests like “启动 OpenStoryline”, “把 OpenStoryline 跑起来”, “用 OpenStoryline 剪视频”.

openstoryline-install

3891
from openclaw/skills

Install, configure, and start FireRed-OpenStoryline from source on a local machine. Use when a user asks to set up OpenStoryline, troubleshoot installation, download required resources, fill config.toml API keys, or launch the MCP and web services, as well as Chinese requests like “安装 OpenStoryline”, “配置 OpenStoryline”, “启动 OpenStoryline”, “把 OpenStoryline 跑起来”, “修复 OpenStoryline 安装问题”, or “排查 OpenStoryline 启动失败”.

hallucinatingsplines

3891
from openclaw/skills

Build and manage cities autonomously on Hallucinating Splines — the headless Micropolis simulator with a REST API and MCP server for AI agents.

offline-llama

3891
from openclaw/skills

Autonomously manage and use local Ollama models for continuous operation without internet dependency. Includes model health monitoring, automatic fallback, and self-healing capabilities.