Exact wire format for every header the SDK and Bondi exchange.
When Bondi calls your BondiAction endpoint from a workflow, it sets:
| Header | Value | Notes |
|---|---|---|
Content-Type |
application/json |
Always JSON — even for empty bodies |
x-bondi-signature |
sha256={64-char hex} |
HMAC-SHA256 of {ts}.{action}.{rawBody}, prefixed with sha256= |
x-bondi-timestamp |
1761234567 |
Unix seconds (integer string), at signing time |
x-bondi-action |
e.g. createContact |
Matches name from your @BondiAction / defineAction |
Your service must:
x-bondi-timestamp.See webhook-verification.md for code samples in Node, Python, Go, Ruby.
When the SDK emits a trigger, it sends:
POST {BONDI_API_URL}/integrations/custom/{workspaceId}/{slug}/emit
| Header | Value | Notes |
|---|---|---|
Content-Type |
application/json |
|
x-bondi-signature |
sha256={64-char hex} |
Same algorithm as outbound |
x-bondi-timestamp |
1761234567 |
|
x-bondi-action |
trigger name (e.g. contact.created) |
Matches name from defineTrigger / @BondiTrigger |
Body:
{"event":"contact.created","data":{"id":"1","email":"alice@example.com"}}
The SDK handles all of this — you just call .emit(payload).
When npx bondi sync runs:
PUT {BONDI_API_URL}/integrations/custom/{workspaceId}/{slug}/sync
| Header | Value | Notes |
|---|---|---|
Content-Type |
application/json |
|
x-bondi-signature |
sha256={64-char hex} |
Same algorithm; action = "sync" |
x-bondi-timestamp |
1761234567 |
|
x-bondi-action |
sync |
Constant string |
Body:
{"definition":{...serialized JSON Schema...},"version":"1.2.0"}
(Only relevant for Bondi's own platform events with internalMode: true.)
POST {BONDI_API_URL}/internal/platform-events
| Header | Value | Notes |
|---|---|---|
Content-Type |
application/json |
|
x-internal-api-key |
{INTERNAL_API_KEY} |
Shared secret; not HMAC |
Body:
{
"providerSlug": "bondi-platform",
"workspaceId": "ws-...",
"event": "user.registered",
"data": {...},
"timestamp": "2026-04-26T12:34:56.000Z"
}
External customers should never call this. See internal-mode.md.
| Code | Meaning | Action |
|---|---|---|
202 Accepted |
Trigger received and queued for dispatch | None — fire-and-forget OK |
200 OK |
Sync succeeded | None |
400 |
Invalid event name, missing headers, or invalid definition | Check error body — fix request |
401 |
Invalid HMAC signature or expired timestamp | Verify token, fix clock, re-send |
404 |
Custom integration slug not found in workspace | Run npx bondi sync first |
409 |
Soft delete blocked by active workflows | Resolve workflows referencing the integration |
410 |
Integration deactivated | Re-create or contact support |
429 |
Rate limit exceeded | Throttle: 60/min/integration, 1000/hr/workspace |