Lark guide
Bring your own Lark (open.larksuite.com) or Feishu (open.feishu.cn) custom app: registration proves the credentials, you paste one URL into the console, and the bot answers as your agent in p2p chats and groups.
Prerequisites
- A custom app in the Lark Developer Console (or the Feishu console) with the Bot capability enabled and these permissions granted:
| Scope | What stops working without it |
|---|---|
im:message, im:message.p2p_msg:readonly | the bot receives nothing in a direct chat |
im:message.group_at_msg:readonly | the bot receives nothing when mentioned in a group |
im:message.group_msg | ordinary group follow-ups without a bot mention are not delivered; requires administrator approval |
im:message:send_as_bot | the bot cannot reply |
im:message:update | a streamed reply cannot be revised — it arrives as one block at the end |
im:message:recall | a reply that gets shorter leaves its stale tail behind |
im:message.reactions:write_only | no working markers (⏳ → ✅) |
im:message.reactions:read | a marker Lark refuses to take down cannot be checked, so a turn whose ⏳ is already gone never gets its ✅ |
Permissions take effect when you publish an app version. Request the all-group-messages scope only when you want group conversations to continue without a mention; it permits receiving messages in every group containing the bot. With mention-only permission, mention the bot on every turn. See the official SDK permission guidance.
- Its App ID and App Secret (Credentials & Basic Info) and the Verification Token from Event Subscriptions. If you set an Encrypt Key there, pass it too — deliveries then arrive encrypted and signed.
- An AgentSky API token with write scope.
Register the channel app
The developer console walks the same checklist, or over the API:
curl -s -X POST https://api.agentsky.dev/v1/channels/apps \
-H "Authorization: Bearer $AST_TOKEN" -H 'content-type: application/json' \
-d '{"platform": "lark", "label": "My Lark app", "credentials": {"app_id": "cli_...", "app_secret": "...", "verification_token": "...", "domain": "lark"}}'
# -> setup: { "events_url": "https://.../webhooks/lark/app_..." }Registration mints a tenant token and reads the bot's identity — a wrong secret answers 400 lark_error. The stored credential keys grow bot_open_id and bot_name. domain is lark (default) or feishu; encrypt_key is optional.
Finish in the console. Lark has no API for event subscriptions: paste setup.events_url as the Request URL under Event Subscriptions (Lark verifies it with a challenge immediately), add the im.message.receive_v1 event, then publish an app version so the bot is available to your organization.
Connect
curl -s -X POST https://api.agentsky.dev/v1/channels/connections \
-H "Authorization: Bearer $AST_TOKEN" -H 'content-type: application/json' \
-d '{"platform": "lark", "app": "app_...", "destination": {"session": "sess-..."}}'
# -> connect: { "url": "https://applink.larksuite.com/client/bot/open?appId=cli_...", "code": "LINK:…", "app_id": "cli_...", "expires_at": "…" }connect.url opens the bot's chat inside Lark; the end user sends connect.code there and the chat claims the connection. To connect a group, add the bot to the group and send the code in the group with an @mention of the bot. The connection's thread is then lark:{app}:GROUP:{chat_id} and the service subscribes that conversation after the claim. With administrator-approved im:message.group_msg permission, subsequent messages need no mention; with mention-only permission, every follow-up must mention the bot. Unconnected, unmentioned groups are not routed to an agent. Codes expire after 15 minutes, and a code minted for your app is refused if sent to any other bot. The hosted connect page renders this ceremony for you.
Capabilities
| threads | reactions | markers | proactive | markdown | modals | ephemeral | streaming |
|---|---|---|---|---|---|---|---|
| ✗ | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✓ |
Markdown renders as an interactive card (Lark's markdown element: bold, italic, links, inline code, code blocks, lists, headings), which is also what lets replies be edited in place. A raw part is sent as a plain text message. Working markers use Lark's reaction set — OnIt while working, DONE on completion, CrossMark on failure. Thread ids are lark:P2P:{chat_id} / lark:GROUP:{chat_id} (with the app id as the second segment on your own app).
Troubleshooting
- The console refuses the Request URL — the app was registered with a different verification token than the console shows; rotate the app's credentials (
PATCH /v1/channels/apps/{id}) with the current token and try again. - Nothing arrives from a group — the bot only receives group messages that @mention it unless the app holds the receive-all-group-messages scope; mention the bot, and check the event subscription includes
im.message.receive_v1. - Replies fail with a permission error — grant
im:message:send_as_bot(and the reactions scope for markers) and re-publish the app version; permissions take effect on publish. - Encrypted deliveries answer 401 — the
encrypt_keycredential does not match the console's Encrypt Key.
AgentSky