旨在让开发者便捷的调用飞书开放API、处理订阅的事件、处理服务端推送的卡片行为等。
Feishu Open Platform offers a series of server-side atomic APIs to achieve diverse functionalities. However, actual coding requires additional work, such as obtaining and maintaining access tokens, encrypting and decrypting data, and verifying request signatures. Furthermore, the lack of semantic descriptions for function calls and type system support can increase coding burdens.
To address these issues, Feishu Open Platform has developed the Open Interface SDK, which incorporates all lengthy logic processes, provides a comprehensive type system, and offers a semantic programming interface to enhance the coding experience.
- 开发前准备(安装) / Preparations before development(Install SDK)
- 调用服务端 API / Calling Server-side APIs
- 处理事件订阅 / Handle Events
- 处理卡片回调 / Handle Card Callbacks
- 常见问题 / SDK FAQs
- Channel 与 Agent 接入 / Channel and Agent Integration / English
LarkChannel is a high-level conversation facade for Agent and bot scenarios. It brings event intake, message normalization, safety policy gates, replies, streaming output, media upload/download, card actions and reactions into one Java entry point.
Use Channel when you are building a conversational bot, AI Agent, support assistant, knowledge-base assistant or any service that needs to receive Feishu/Lark messages and reply in the same chat context. For small one-off API calls, use the regular Client; for long-running chat workflows, Channel handles the surrounding plumbing.
Key entry points:
- Create a channel with
LarkChannelFactory.createLarkChannel(...). - Call
connect()before processing inbound events; it returnsCompletableFuture<BotIdentity>. - Listen with
channel.on("message", handler),channel.on("cardAction", handler),channel.on("reject", handler)and related event names. - Reply with
send(...), stream incremental output withstream(...), and usedownloadResource(...)for image/file content. - Configure
policy(...)for group allowlists, direct-message behavior, mention requirements and mention-all handling. - Use
includeRawEvent(true)only when handlers need the original event body.
See CHANNEL.en.md for the English guide and CHANNEL.md for the Chinese guide.
The SDK provides RegisterApp.register(...) for one-click app creation based on OAuth 2.0 Device Authorization Grant (RFC 8628).
It returns a verification URL that users can open in Feishu/Lark to authorize and automatically register an app, then obtain the app credentials without manually creating one in the developer console.
import com.lark.oapi.scene.registration.AppPreset;
import com.lark.oapi.scene.registration.QRCodeInfo;
import com.lark.oapi.scene.registration.RegisterApp;
import com.lark.oapi.scene.registration.RegisterAppException;
import com.lark.oapi.scene.registration.RegisterAppOptions;
import com.lark.oapi.scene.registration.RegisterAppResult;
public class Sample {
public static void main(String[] args) {
try {
RegisterAppResult result = RegisterApp.register(
RegisterAppOptions.newBuilder()
.source("test")
.appPreset(AppPreset.newBuilder()
.avatars(
"https://s1-imfile.feishucdn.com/static-resource/v1/v3_00cj_d6bebede-c56b-40a2-b767-8e9da07f3b3g",
"https://s1-imfile.feishucdn.com/static-resource/v1/v2_bc5d2075-fcbd-41f8-bfe3-5a5ecbf0f7dg"
)
.name("{user}'s app")
.desc("Created by the business platform")
.build())
.onQRCode(info -> {
System.out.println("Please scan the QR code:");
System.out.println(info.getUrl());
System.out.println(String.format("Expires in %s seconds", info.getExpireIn()));
})
.onStatusChange(info -> System.out.println(
"Status: " + info.getStatus()
+ (info.getInterval() > 0
? String.format(" (interval: %ss)", info.getInterval())
: "")
))
.build()
);
System.out.println("App ID: " + result.getClientId());
System.out.println("App Secret: " + result.getClientSecret());
System.out.println("User Info: " + result.getUserInfo());
} catch (RegisterAppException e) {
System.err.println("Failed: " + e.getCode() + " " + e.getDescription());
}
}
}Real runnable demo:
When creating an app, use addons to incrementally request scopes, event subscriptions and callbacks on top of the platform base template. They are pre-filled into the confirm page shown after the user opens the verification URL, and take effect after the user confirms:
import com.lark.oapi.scene.registration.AppAddons;
// Create: incrementally request scopes/events/callbacks, and only allow creating a new app.
RegisterApp.register(RegisterAppOptions.newBuilder()
.addons(AppAddons.newBuilder()
.tenantScopes("im:message:send_as_bot")
.userScopes("calendar:calendar:read")
.tenantEvents("im.message.receive_v1")
.callbacks("card.action.trigger")
.build())
.createOnly(true)
.onQRCode(info -> System.out.println(info.getUrl()))
.build());
// Update: pass the appId of an existing app to let the user confirm incremental config changes.
RegisterApp.register(RegisterAppOptions.newBuilder()
.appId("cli_xxx")
.addons(AppAddons.newBuilder()
.tenantScopes("drive:drive.metadata:readonly")
.build())
.onQRCode(info -> System.out.println(info.getUrl()))
.build());Notes:
addonsis additive only. Items are merged on top of the base template; base permissions cannot be removed.- Only the 5 public config types are supported: tenant/user scopes, tenant/user events, and callbacks. Sensitive config such as event request URLs,
security.*, and encrypt keys cannot travel throughaddons; use the update application config OpenAPI instead. - The SDK validates the shape and non-empty values, not whether scope/event/callback names exist in the platform catalog.
| Parameter | Description | Type | Required | Default |
|---|---|---|---|---|
source |
Source identifier, appended to the QR code URL source parameter as java-sdk/{source} |
String |
No | - |
domain |
Custom Feishu accounts base URL | String |
No | https://accounts.feishu.cn |
larkDomain |
Custom Lark accounts base URL, used when tenant brand is detected as Lark | String |
No | https://accounts.larksuite.com |
appPreset |
Pre-fill values for the app creation page. All fields are optional; users can still edit them on the page. The SDK URL-encodes raw values automatically. | AppPreset |
No | - |
appPreset.avatar |
App avatar URL candidates. Supports 1-6 URLs; the first one is selected by default. Page/server handles image rendering rules such as png/jpg/jpeg/webp/gif and GIF frame sampling. | String / String[] / List<String> |
No | - |
appPreset.name |
App name. Supports the {user} placeholder, replaced by the app creation page with the scanning user's name. |
String |
No | - |
appPreset.desc |
App description. Supports the {user} placeholder. |
String |
No | - |
addons |
Incremental scopes/events/callbacks pre-filled into the confirm page. | AppAddons |
No | - |
addons.scopes.tenant |
App-identity scopes, for example im:message:send_as_bot. |
String[] / List<String> |
No | - |
addons.scopes.user |
User-identity scopes, for example calendar:calendar:read. |
String[] / List<String> |
No | - |
addons.events.items.tenant |
App-identity events, for example im.message.receive_v1. |
String[] / List<String> |
No | - |
addons.events.items.user |
User-identity events, for example calendar.calendar.event.changed_v4. |
String[] / List<String> |
No | - |
addons.callbacks.items |
Callbacks, for example card.action.trigger. |
String[] / List<String> |
No | - |
createOnly |
When true, the landing page only allows creating a new app and hides the select-existing-app entry. |
boolean |
No | false |
appId |
App ID (cli_ prefix) of an existing app. When set, the flow updates that app's config by asking the user to confirm the diff brought by addons. The page ignores it when createOnly is true. |
String |
No | - |
onQRCode |
Callback when the verification URL is ready. Receives QRCodeInfo with url and expireIn |
Consumer<QRCodeInfo> |
Yes | - |
onStatusChange |
Callback on polling status changes. Receives StatusChangeInfo |
Consumer<StatusChangeInfo> |
No | - |
| Field | Type | Description |
|---|---|---|
clientId |
String |
App ID |
clientSecret |
String |
App Secret |
userInfo |
UserInfo |
Scanning user info |
userInfo.openId |
String |
User's open_id |
userInfo.tenantBrand |
String |
"feishu" or "lark" |
| Status | Description |
|---|---|
polling |
Authorization is still pending |
slow_down |
The server asks the client to slow down polling; interval contains the new interval in seconds |
domain_switched |
The SDK detected a Lark tenant and switched polling to larkDomain |
RegisterAppException contains code and description fields:
| code | Description |
|---|---|
access_denied |
User denied the authorization |
expired_token |
QR code expired or polling timed out |
abort |
Registration was canceled via thread interruption |
invalid_response |
The service returned an unexpected response |
我们还基于 SDK 封装了常用的 API 组合调用及业务场景示例,如:
- 消息
- 通讯录
- 多维表格
- 电子表格
- 教程
更多示例可参考:https://github.com/larksuite/oapi-sdk-java-demo
使用 MIT