Skip to content

Larksuite (Feishu)

Feishu (国内版) et Lark Suite (海外版) partagent la même surface OpenAPI. Le provider Ongrid les traite comme une seule intégration ; choisissez la base URL qui matche votre tenant.

ModeCe que ça fait
NotificationPush d'alerte vers un groupe Feishu/Lark via webhook de bot personnalisé.
Pont IMChat agent bidirectionnel via la long-connection WebSocket.

Mode notification (bot personnalisé)

Le sender Feishu poste un payload de bot personnalisé Feishu / Lark à l'URL de webhook que votre administrateur de bot fournit. Forme du payload :

json
{
  "msg_type": "text",
  "content": {"text": "[CRITICAL] swap_high node-01\nswap_in_pages > 1000 for 5m\nsource: alert\ndedupe: alert:swap_high:device=7"},
  "timestamp": "1717012345",
  "sign": "<base64-hmac>"
}

Signature — champ sign

Quand vous activez 签名校验 (vérification de signature) sur le bot personnalisé Feishu, Feishu vous donne un secret partagé. Le sender calcule le champ sign comme :

text
stringToSign = timestamp + "\n" + secret
sign         = base64(HMAC-SHA256(key=stringToSign, message=<empty>))

Oui — le secret prend le rôle à la fois de matière de clé pour HMAC et de partie du string-to-sign. C'est l'algorithme que Feishu documente, et c'est ce que signFeishu implémente.

Si vous laissez le champ Secret vide, Ongrid poste sans sign / timestamp — utilisable seulement quand votre bot a la vérification de signature désactivée (ou a une allowlist IP à la place).

Setup

  1. Dans le groupe Feishu → 设置 → 群机器人 → 添加机器人 → 自定义机器人. Donnez-lui un nom et un avatar.
  2. Cochez 签名校验 ; copiez le secret.
  3. Copiez l'URL du webhook — ressemble à https://open.feishu.cn/open-apis/bot/v2/hook/<uuid> (ou …/open.larksuite.com/… pour Lark Suite).
  4. Dans Ongrid : Settings → Channels → New → Provider = feishu → Endpoint = l'URL de webhook → Secret = le secret de signature.

Bot personnalisé ≠ App

Le mode notification utilise un bot personnalisé (scope groupe, webhook uniquement). Le mode pont IM utilise une app Feishu (scope tenant, OAuth + events). Ce sont des concepts différents ; les credentials ne se chevauchent pas.

Mode pont IM (stream long-connection)

Le pont bidirectionnel utilise la long-connection Feishu livrée par le client officiel github.com/larksuite/oapi-sdk-go/v3/ws. Le manager se connecte à l'endpoint d'événement de Feishu et Feishu pousse les événements sur le WebSocket — aucune URL de webhook publique requise.

Pourquoi stream et pas webhook

Le mode webhook (mode=webhook) est supporté dans le schéma pour rétro-compat, mais le stream long-connection est le chemin recommandé :

  • Pas d'ingress public nécessaire sur le manager.
  • Réutilise le reconnect-with-backoff du superviseur (le SDK a son propre reconnect ; le superviseur ajoute une boucle externe pour les échecs terminaux).
  • Le SDK gère la vérification de signature + le déchiffrement AES en interne, donc vous n'avez pas besoin de remplir encrypt_key pour la variante stream — c'est webhook-only.

Mapping des credentials

Colonne im_appsSignification Feishu
provider"feishu"
mode"stream" (recommandé) ou "webhook"
app_idFeishu app_id (cli_…).
app_secretFeishu app_secret.
verify_tokenOptionnel. Utilisé par la vérification de signature en mode webhook.
encrypt_keyRequis en mode webhook, ignoré en mode stream.
allow_fromOptionnel. Feishu est gaté par tenant donc l'allowlist est non-obligatoire.

default_locale

Mettez zh pour un tenant Feishu dont les opérateurs écrivent en chinois, en pour une équipe Lark anglophone. Vide (défaut) signifie que le LLM mirror l'utilisateur.

Setup

  1. 开发者后台 → 创建企业自建应用. Obtenez app_id + app_secret.
  2. 应用功能 → 机器人 → activer. Ajoutez le bot à votre chat de test.
  3. 权限管理 → accorder :
    • im:message — lire les messages adressés au bot.
    • im:message.group_at_msg — événements de mention de groupe.
    • im:message.p2p_msg — événements de DM.
    • im:message:send_as_botSendText / EditText.
  4. 事件订阅 → 长连接模式 (long-connection) → activer.
  5. Dans Ongrid : Settings → IM bridge → New → Provider = feishu → Mode = stream → coller app_id + app_secret. Save et Enable.
  6. @ le bot dans le chat. L'agent le récupère.

Mise en cache tenant_access_token

Les appels sortants (SendText, EditText) s'authentifient avec un tenant_access_token, rafraîchi proactivement quand on est à moins de 200s de l'expiration. Le token est cached par instance de Client, protégé par un sync.Mutex ; rotater les credentials signifie reconstruire le client. Voir tenantAccessToken.

msg_type est requis aussi sur les edits

Le PUT /open-apis/im/v1/messages/<id> de Feishu requiert msg_type dans le corps — l'omettre renvoie code: 99992402 (échec de validation de champ) même si la page de doc pour « edit message » ne le rend pas évident. Le provider envoie toujours msg_type: text.

Mode webhook (legacy, conservé pour compatibilité)

Le mode webhook est encore sélectionnable dans l'UI ; le superviseur vérifie les signatures et déchiffre les payloads lui-même.

Vérification de signature

Le handler HTTP lit X-Lark-Signature et exécute VerifyEventSignature :

text
sig = sha256(timestamp + nonce + encrypt_key + body), hex-encoded

Oui — SHA-256, pas HMAC. L'encrypt_key joue le rôle de secret partagé dans l'input du hash. Le vérificateur ne panique jamais sur un input mauvais ; un mismatch renvoie ErrBadSignature.

Déchiffrement du payload

Quand encrypt_key est posé, Feishu enveloppe le JSON d'événement en AES-256-CBC. Le déchiffrement utilise :

  • Clé : SHA-256(encrypt_key).
  • IV : les 16 premiers octets du ciphertext base64-décodé.
  • Padding : PKCS#7.

Voir DecryptEvent.

Choisissez le mode stream si possible

Le mode webhook nécessite un endpoint HTTPS public et la plomberie encrypt_key ci-dessus. Le stream long-connection évite les deux. Tendez la main vers le mode webhook seulement quand vous en avez spécifiquement besoin (par ex. intégrer les événements Feishu à un routeur de webhooks publics existant).

Particularités

  • Le client stream Feishu n'impose pas allow_from aujourd'hui — la plateforme Feishu elle-même est gatée par tenant, donc seuls les membres de l'entreprise atteignent le bot. Si votre tenant a des invités / collaborateurs externes, remplissez allow_from avec leurs valeurs open_id pour verrouiller la conversation plus loin.
  • Les stickers, fichiers, cartes et messages riches sont droppés (seul msg_type == "text" déclenche l'agent). Même contrat S1 que Telegram / Slack.
  • Le champ RootId est capturé comme ImThread.ImThreadID pour que les réponses à l'intérieur d'un thread continuent la même session — pas besoin pour l'utilisateur de reset le contexte par question.