webhooks
Webhook notifications for render completion and file processing events. Configure an endpoint, verify HMAC signatures, and handle real-time status payloads.
Works with
---
name: webhooks
description: Webhook notifications for render completion and file processing events. Configure an endpoint, verify HMAC signatures, and handle real-time status payloads.
license: MIT
---
# Webhooks
Use webhooks to receive real-time HTTP POST notifications when a render completes or a file finishes processing. Use them instead of polling `getRenderProgress`/`getFileProcessingProgress`.
No SDK function registers a webhook. Configure one on an API key, through the dashboard (Settings → API Keys, or `editframe.com/resource/api_keys`). Set a **Webhook URL** (this must use HTTPS). Select which **Webhook Events** (topics) to receive. When you create or update the key, the dashboard generates a **Webhook Secret**, used to sign deliveries. Copy this secret and store it alongside the API key.
## Handling a Webhook
```typescript
import express from "express";
import crypto from "node:crypto";
const app = express();
// Use express.raw(), not express.json(). Signature verification needs the
// exact raw bytes. Re-serializing parsed JSON can reorder keys or change
// whitespace, which changes the hash and breaks verification.
app.post("/webhooks/editframe", express.raw({ type: "*/*" }), (req, res) => {
const signature = req.headers["x-webhook-signature"] as string;
const rawBody = req.body as Buffer;
const expected = crypto
.createHmac("sha256", process.env.EDITFRAME_WEBHOOK_SECRET!)
.update(rawBody)
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(signature, "hex"), Buffer.from(expected, "hex"))) {
return res.status(401).send("Invalid signature");
}
res.status(200).send("OK"); // respond fast — Editframe times out at 30s
const payload = JSON.parse(rawBody.toString("utf-8"));
processWebhookEvent(payload).catch(console.error); // do real work after responding
});
```
Every request carries an `X-Webhook-Signature` header: `HMAC-SHA256(webhook_secret, raw_json_body)`, hex-encoded. Verify with `crypto.timingSafeEqual`, not `===`.
## Payload
```typescript
{ topic: string, data: {...} }
```
### Render topics: `render.created`, `render.pending`, `render.rendering`, `render.completed`, `render.failed`
`data` includes `id`, `status`, `created_at`, `completed_at`, `failed_at`, `width`, `height`, `fps`, `byte_size`, `duration_ms`, `md5`, `metadata`, `expires_at` (`null` = permanent), `download_url` (populated once complete), `error` (populated on failure).
### File topics: `file.created`, `file.uploading`, `file.processing`, `file.ready`, `file.failed`, `file.updated`
`data` includes `id`, `type` (`video`/`image`/`caption`), `status`, `filename`, `byte_size`, `md5`, `mime_type`, `width`, `height`, `expires_at`. Editframe sends `file.updated` for a file status change that doesn't match one of the other file topics.
### Legacy topics
Editframe still emits these topics, tied to the deprecated per-type file APIs. Do not build a new integration against them.
`image_file.created`, `isobmff_file.created`, `isobmff_track.created`, `unprocessed_file.created`.
## Delivery
- Each event arrives as one HTTP POST, with a JSON body.
- Editframe retries on a fixed 10-second interval, up to 3 attempts total, with a 30-second timeout per attempt. After the final failed attempt, it marks the event failed. This is visible in the dashboard's delivery log. Editframe does not retry or replay the event further.
- Editframe may deliver an event more than once. Key any side effect off `data.id`, or off the topic-and-id pair, to stay idempotent.
- Always hash the **raw** request body for signature verification. Parsing the body, then calling `JSON.stringify` again, can reorder keys or change whitespace. This produces a different hash than the one Editframe signed.
## Testing
```bash
npx editframe webhook -t render.completed # sends a real test event to the URL configured on your API key
```
See the `editframe-api` skill's CLI section for more detail. There is no `--webhookURL` flag. The target URL always comes from the key's dashboard configuration. The dashboard's API key detail page has an equivalent "Test Webhook" button.
For local development, tunnel your dev server, for example with `ngrok http 3000`. Point the API key's Webhook URL at the tunnel URL while you test.More API Design skills
lark-event
larksuite/cli
Lark/Feishu real-time event listening / subscribing / consuming: stream events as NDJSON via `lark-cli event consume <EventKey>` (covers IM messages/reactions/chat changes, Approval status changes, Task updates, VC meeting started/joined/ended, Minutes generated, Whiteboard updated, etc.). Use for Lark bots, real-time message processing, long-running subscribers, streaming webhook/push handlers. Supports `--max-events` / `--timeout` bounded runs and a stderr ready-marker contract — designed for AI agents running as subprocesses.
lark-contact
larksuite/cli
飞书 / Lark 通讯录:按姓名 / 邮箱解析成 open_id,或按 open_id 反查姓名 / 部门 / 邮箱 / 联系方式 / 个人状态 / 签名,以及按关键词搜索当前用户可见的机器人 / 智能体(agent)。当用户提到一个名字要下一步发消息 / 排日程,或拿到 open_id 想查具体信息时使用。不负责部门树遍历、按部门列员工、组织架构图,这类需求走原生 OpenAPI。
lark-openapi-explorer
larksuite/cli
飞书/Lark 原生 OpenAPI 探索:从官方文档库中挖掘未经 CLI 封装的原生 OpenAPI 接口。当用户的需求无法被现有 lark-* skill 或 lark-cli 已注册命令满足,需要查找并调用原生飞书 OpenAPI 时使用。

