Documentation index | 简体中文 | English
All channel construction starts with LarkChannelOptions.newBuilder(appId, appSecret). The top-level options are immutable after build(); nested configuration objects are mutable Java beans so they can be assembled before construction and, for policy only, applied later through updatePolicy.
| Method | Default | Purpose |
|---|---|---|
transport(String) |
websocket |
Select WebSocket or Webhook inbound mode. |
webhook(WebhookOptions) |
empty bean | Configure callback verification/decryption. |
safety(SafetyConfig) |
documented safety defaults | Configure stale, dedup, queue, lock, and batching behavior. |
policy(PolicyConfig) |
documented policy defaults | Configure group and direct-message admission. |
outbound(OutboundConfig) |
documented outbound defaults | Configure splitting, streaming, media, and retries. |
cache(ICache) |
null |
Main-SDK cache plus cross-process seen-event lookup. |
domain(String) |
main-SDK Feishu default | Override OpenAPI and WebSocket domain. |
httpTransport(IHttpTransport) |
main-SDK default | Override HTTP transport. |
httpInstance(RequestOptions) |
null |
Supply request options to main-SDK calls. |
source(String) |
null |
Supply a main-SDK source identifier. |
clientAssertionProvider(...) |
null |
Enable client-assertion authentication. |
oauthBaseUrl(String) |
main-SDK default | Override OAuth/assertion base URL. |
includeRawEvent(boolean) |
false |
Attach original callback data to normalized models. |
includeRawInMessage(boolean) |
false |
Deprecated alias of includeRawEvent. |
The nested default objects are created by the builder. Passing null into nested setters is not uniformly normalized, so application configuration should construct and validate complete objects.
LarkChannelOptions options = LarkChannelOptions.newBuilder(appId, appSecret).build();Read appId and appSecret from a secret manager or runtime environment. Do not log either value. The SDK does not validate arbitrary application input for you; reject null or blank configuration at your process boundary.
For private-key authentication, provide the main SDK's ClientAssertionProvider:
LarkChannelOptions options = LarkChannelOptions.newBuilder(appId, "")
.clientAssertionProvider(clientAssertionProvider)
.build();An empty app secret is appropriate only when a non-null provider supplies valid client assertions. Keep private keys outside this SDK and rotate them through your credential system. oauthBaseUrl(...) can override the assertion/OAuth endpoint base URL when the main SDK deployment requires it.
The supported values are:
| Value | Behavior |
|---|---|
websocket |
Default. Creates the raw WebSocket client; connect() waits for identity and first handshake. |
webhook |
Does not create a WebSocket client. The host obtains createWebhookDispatcher() and attaches it to its HTTP endpoint. |
LarkChannelOptions options = LarkChannelOptions.newBuilder(appId, appSecret)
.transport("websocket")
.build();The preview does not reject unknown transport strings; unknown values behave like a non-WebSocket transport but are unsupported. Validate configuration against exactly websocket or webhook before building the channel.
Webhook verification values are separate from application credentials:
LarkChannelOptions.WebhookOptions webhook = new LarkChannelOptions.WebhookOptions();
webhook.setVerificationToken(verificationToken);
webhook.setEncryptKey(encryptKey);
LarkChannelOptions options = LarkChannelOptions.newBuilder(appId, appSecret)
.transport("webhook")
.webhook(webhook)
.build();See Webhook integration for request handling and lifecycle requirements.
The Channel SDK forwards these settings to the underlying main SDK:
| Builder method | Purpose |
|---|---|
domain(String) |
OpenAPI base domain and WebSocket domain; default is the Feishu domain used by the main SDK. |
httpTransport(IHttpTransport) |
Custom main-SDK HTTP transport. |
httpInstance(RequestOptions) |
Per-client request options used by bot identity and OpenAPI calls. |
cache(ICache) |
Main-SDK cache and Channel cross-process seen-event lookup. |
source(String) |
Source identifier passed to the main SDK. |
clientAssertionProvider(...) |
Private-key client assertion provider. |
oauthBaseUrl(String) |
OAuth base URL override. |
Use one consistent environment/domain for HTTP and WebSocket traffic. Do not accept a domain directly from an untrusted request; configure it from trusted deployment settings.
Normalized events omit the original event body by default:
LarkChannelOptions options = LarkChannelOptions.newBuilder(appId, appSecret)
.includeRawEvent(true)
.build();Enable this only when a handler needs fields that normalization intentionally drops. Raw events can contain identifiers, tenant metadata, message content, and vendor extensions. Avoid retaining or logging them. includeRawInMessage(...) is deprecated; use includeRawEvent(...).
PolicyConfig controls which messages reach the message handler:
| Option | Default | Meaning |
|---|---|---|
groupAllowlist |
empty | Empty permits all groups; otherwise only listed chat IDs pass. |
dmMode |
open |
Supported values are open, disabled, and allowlist. |
dmAllowlist |
empty | Sender open IDs allowed when dmMode=allowlist. |
requireMention |
true |
Group messages must directly mention the bot. |
respondToMentionAll |
false |
Whether @all passes the group mention gate. |
LarkChannelOptions.PolicyConfig policy = new LarkChannelOptions.PolicyConfig();
policy.setGroupAllowlist("oc_allowed_chat");
policy.setDmMode("allowlist");
policy.setDmAllowlist("ou_allowed_user");
policy.setRequireMention(true);
policy.setRespondToMentionAll(false);Unknown dmMode values currently behave like open, so applications must validate the value themselves. See Policy and safety before changing defaults.
| Option | Default |
|---|---|
| Duplicate TTL | 12 hours |
| In-memory duplicate capacity | 5,000 entries |
| Duplicate sweep interval | 5 minutes |
| Stale-message window | 30 minutes |
| Per-chat queue | enabled |
| Process-local processing-lock TTL | 5 minutes |
| Dedup namespace | channel:seen |
| Short-text batch delay | 600 ms |
| Long-text threshold/delay | 1,000 characters / 2,000 ms |
| Batch limit | 8 messages or 4,000 characters |
LarkChannelOptions.SafetyConfig safety = new LarkChannelOptions.SafetyConfig();
safety.setDedupTtlMs(6L * 60L * 60L * 1000L);
safety.setDedupMaxEntries(3000);
safety.setStaleMessageWindowMs(10L * 60L * 1000L);
safety.setChatQueueEnabled(true);
LarkChannelOptions options = LarkChannelOptions.newBuilder(appId, appSecret)
.safety(safety)
.build();Capacity and TTL values must remain positive and bounded in application configuration. A shared ICache helps later duplicate checks observe events marked by another process. The check-and-mark sequence and processing lock are not distributed or atomic, so application side effects must remain idempotent across instances.
| Option | Default | Purpose |
|---|---|---|
textChunkLimit |
3,500 | Split long text and Markdown. |
streamThrottleMs |
100 | Minimum timed flush interval. |
streamThrottleChars |
50 | Character-based stream flush threshold. |
streamInitialText |
Thinking... |
Initial Markdown streaming card text. |
ssrfGuardEnabled |
true |
Reject private/reserved remote media destinations. |
ssrfAllowlist |
empty | Exact normalized hosts permitted through the address guard. |
| retry max attempts | 3 | Total attempts for retryable outbound failures. |
| retry base delay | 500 ms | First backoff delay. |
allowedFileDirs |
empty | No additional directory restriction; any readable non-blocked local path can pass. Configure this in production. |
LarkChannelOptions.OutboundConfig outbound = new LarkChannelOptions.OutboundConfig();
outbound.setTextChunkLimit(3000);
outbound.setStreamInitialText("Generating...");
outbound.setAllowedFileDirs(java.util.Collections.singletonList("/srv/bot/uploads"));
LarkChannelOptions.RetryConfig retry = new LarkChannelOptions.RetryConfig();
retry.setMaxAttempts(3);
retry.setBaseDelayMs(500L);
outbound.setRetry(retry);
LarkChannelOptions options = LarkChannelOptions.newBuilder(appId, appSecret)
.outbound(outbound)
.build();Keep SSRF protection enabled. An allowlisted host bypasses private/reserved-address rejection, so add only infrastructure-controlled hosts. See Media and Sending messages.
LarkChannelOptions.PolicyConfig policy = new LarkChannelOptions.PolicyConfig();
policy.setGroupAllowlist("oc_support_group");
policy.setDmMode("allowlist");
policy.setDmAllowlist("ou_operator");
LarkChannelOptions.SafetyConfig safety = new LarkChannelOptions.SafetyConfig();
safety.setStaleMessageWindowMs(15L * 60L * 1000L);
LarkChannelOptions.OutboundConfig outbound = new LarkChannelOptions.OutboundConfig();
outbound.setAllowedFileDirs(java.util.Collections.singletonList("/srv/channel/files"));
LarkChannel channel = LarkChannelFactory.createLarkChannel(
LarkChannelOptions.newBuilder(appId, appSecret)
.transport("websocket")
.policy(policy)
.safety(safety)
.outbound(outbound)
.includeRawEvent(false)
.build());Treat configuration loading as an application boundary: validate type, range, enum values, paths, and domains before constructing these objects.
- Blank app credentials without a valid
ClientAssertionProviderlead to authentication or connection failure. - Any transport string other than exact
websocketorwebhookis unsupported and may silently behave as non-WebSocket. - Unknown
dmModevalues widen behavior to open; validate the enum. - Empty
allowedFileDirsdoes not block local files; configure a narrow production directory list. - Zero/negative capacities or excessively large TTL/batch/retry values can remove resource bounds or create long stalls.
- A custom
domaindoes not automatically prove the chosen OAuth endpoint and network environment are consistent; validate bothdomainandoauthBaseUrl. - Enabling raw events can expose extra user and tenant data to application memory and logs.