Webhook Trigger
Create a Webhook, bind API Key authentication (HMAC for legacy integrations), and map payload variables so external systems can drive your workflows.
A Webhook lets external systems (GitHub, CI/CD, Lark, IoT, an upstream API) start a workflow execution directly via HTTP POST. Recommended approach: bind the Webhook to an API Key with the WEBHOOK_TRIGGER scope and authenticate trigger requests with that Key.
Create a Webhook and Bind an API Key
- Under Console → Account settings → API keys, create a Key and check the scope
WEBHOOK_TRIGGER(seeAPI Keys and Scopes) - Create a Webhook from the Webhook list or the workflow details page, choose the target workflow, and bind this Key. The creator needs edit permission on the workflow, and the bound Key must be their own
You can also use the management API (with a logged-in console session):
curl -X POST https://braidrun.com/api/webhooks \
-H "Authorization: Bearer <console-token>" \
-H "Content-Type: application/json" \
-d '{
"workflowId": "<workflow-id>",
"name": "GitHub Push Webhook",
"apiKeyId": "<api-key-id>",
"variableMapping": {
"branch": "ref",
"repo_name": "repo"
}
}'The response includes a unique webhook-id. The trigger URL is:
POST https://braidrun.com/api/webhooks/<webhook-id>/triggerWebhook count follows your plan: Free has none, Pro 3, Team 10, Enterprise unlimited.
Trigger Workflow
curl -X POST https://braidrun.com/api/webhooks/<webhook-id>/trigger \
-H "Authorization: Bearer dyk_<id>_<secret>" \
-H "Content-Type: application/json" \
-d '{
"ref": "refs/heads/main",
"repo": "my-app"
}'Credentials can be passed in three ways, which the server checks in this order:
Authorization: Bearer dyk_<id>_<secret> # 推荐
X-API-Key: dyk_<id>_<secret> # 无法自定义 Authorization 头时
POST .../trigger?api_key=dyk_<id>_<secret> # 仅限无法设置 header 的场景Successful trigger returns:
{
"executionId": "exec_a3b9c8...",
"webhookId": "<webhook-id>",
"workflowId": "<workflow-id>",
"status": "PENDING",
"startedAt": 1735632891234
}The request body must be a JSON object, up to 1 MB. An empty body is treated as an empty object; invalid JSON returns 400.
Variable Mapping
Without variableMapping, top-level string, number, and boolean fields in the payload map to workflow variables of the same name automatically; nested objects and arrays are excluded from automatic mapping.
To rename, configure variableMapping : the key is the workflow variable name, the value is the top-level payload field name. Only top-level fields are supported; nested path lookups are not.
# Webhook 配置
"variableMapping": { "branch": "ref", "repo_name": "repo" }
# 触发 payload
{ "ref": "refs/heads/main", "repo": "my-app" }
# 工作流实际拿到的输入
{ "branch": "refs/heads/main", "repo_name": "my-app" }If a mapped field is missing from the payload, the variable is not injected and the default value in the workflow template still applies (it won't be overwritten with an empty string).
HMAC Signatures (for Legacy Integrations)
A Webhook with no API Key bound but with secretKey set uses the legacy HMAC mode: the trigger request must include a signature in the header:
X-Webhook-Signature: sha256=<hex(HMAC-SHA256(rawRequestBody, secretKey))>Signature = HmacSHA256(rawRequestBody, secretKey) , output as a hex string, with or without the sha256= prefix. A mismatch returns 401.
The signature is the original byte stream. Do not do formatting/key sorting before calculation, otherwise the signature will not match.
Webhooks that have been bound to an API Key no longer accept HMAC signatures, even if the old secretKey field still has a value. The interface allows switching back to HMAC mode; the shared key should be re-confirmed when switching, and clearApiKeyId needs to be set to true when calling the interface. Webhooks that are not configured for both authentications do not verify the identity when triggered. The URL itself is equivalent to the credentials. It is only recommended to be used in a controlled debugging environment.
The legacy trigger path POST /api/webhook-trigger/{webhookId} is still available with identical behavior; use the canonical path above for new integrations.
Restrict source IP
You can fill in the source IP whitelist in the Webhook configuration. Supports a single IPv4/IPv6 address and CIDR network segment, up to 100 entries; leaving blank means no limit. After configuration, requests that pass authentication but do not match the source address return 403.
203.0.113.42
198.51.100.0/24
2001:db8:1234::/48When passing through a reverse proxy or gateway, the client address recognized by the platform depends on the deployer's trusted proxy configuration. After enabling the whitelist, please first send a test request from the real upstream to avoid mistaken interception.
Error Responses
| Status Code | Meaning |
|---|---|
400 | The request body is not valid JSON |
401 | The API Key is invalid, lacks the WEBHOOK_TRIGGER scope, isn't the key bound to this Webhook, or the HMAC signature doesn't match |
403 | The source IP is not in the whitelist |
404 | The webhook-id doesn't exist |
409 | The Webhook is disabled |
429 | Triggered too frequently; the response includes Retry-After and X-RateLimit-* headers |
Common Access Scenarios
- GitHub push — Map the branch name and commit author to variables; the workflow builds, tests, and deploys automatically
- CI 系统 — Build completed → Webhook triggers subsequent release pipeline
- Lark / 飞书机器人 — Trigger operational batch processing after receiving a specific command
- IoT 上报 — Device alarm → Webhook triggers troubleshooting workflow and converges alarms
Management Endpoints
List GET /api/webhooks, update PUT /api/webhooks/{id}, delete DELETE /api/webhooks/{id}, plus GET /api/webhooks/{id}/stats returns trigger stats; all of these are authenticated console endpoints.
When Service Restarts
The platform does not automatically replay the original Webhook request. Executions created by Webhook are also explicitly excluded from the automatic continuation of ordinary crash recovery, even if the workflow has recovery turned on; after interruption, it will remain INTERRUPTED, waiting for manual judgment. The controlled migration performed by the platform during a rolling release is a separate operations process and is not equivalent to ordinary crash recovery.
If you are waiting for manual_approval when you interrupt, the approval record will be retained, but do not assume that the old execution process will resume itself after approval; please go back to the execution details to confirm the final status, and manually rerun from the safe step as needed.
If the upstream resends the same payload, the platform will create a new execution and will not automatically deduplicate the original execution. When including side effects such as writing databases, sending messages, and charging fees, please use business idempotent keys in the workflow.