Sema delivers ITEM_READY events to your webhook endpoint using the Standard Webhooks signing format.
Headers (Standard Webhooks)¶
Each webhook request includes:
webhook-id: unique message id (use as idempotency key)webhook-timestamp: unix timestamp (seconds)webhook-signature: signature string (format:v1,<base64>)
Signature verification¶
Signed content:
Use the webhook secret exactly as returned when you create or update an inbox (e.g. whsec_...). To verify signatures, compute HMAC over {webhook-id}.{webhook-timestamp}.{raw_body} using the decoded secret: if the value has a whsec_ prefix, strip it and base64-decode the remainder to get the key; otherwise use the raw value. The Standard Webhooks spec describes the scheme.
The official Python and Node.js SDKs implement verification and accept the secret as returned by the API.
Request body (v1 envelope)¶
The webhook body is a versioned envelope (enterprise-style contract). It always includes:
schema_version(currently"1.0")event_type(currently"ITEM_READY")occurred_attenant_id,inbox_id,item_idinbound_channel("api"or"email")payload_mode("full"or"thin")deliverable(payload data)
Thin payload¶
Thin payloads include stable references only:
{
"schema_version": "1.0",
"tenant_id": "00000000-0000-0000-0000-000000000000",
"inbox_id": "00000000-0000-0000-0000-000000000000",
"item_id": "00000000-0000-0000-0000-000000000000",
"inbound_channel": "api",
"event_type": "ITEM_READY",
"occurred_at": "2026-01-25T00:00:00Z",
"payload_mode": "thin",
"deliverable": {
"raw_ref": "s3://.../raw.eml",
"normalized_ref": "s3://.../normalized.json"
}
}
Full payload¶
Full payloads include additional metadata and attachments:
{
"schema_version": "1.0",
"tenant_id": "00000000-0000-0000-0000-000000000000",
"inbox_id": "00000000-0000-0000-0000-000000000000",
"item_id": "00000000-0000-0000-0000-000000000000",
"inbound_channel": "email",
"event_type": "ITEM_READY",
"occurred_at": "2026-01-25T00:00:00Z",
"payload_mode": "full",
"deliverable": {
"raw_ref": "s3://.../raw.eml",
"normalized_ref": "s3://.../normalized.json",
"sender": {
"address": "sender@example.com",
"display_name": "Example Sender",
"domain": "example.com",
"verified": false
},
"content_summary": {
"subject": "Bug Report",
"body_preview": "See the screenshot below...",
"body_html": "<p>See the screenshot below:</p><img src=\"cid:img001@example.com\">"
},
"attachments": [
{
"filename": "screenshot.png",
"content_type": "image/png",
"size_bytes": 54321,
"ref": "s3://.../attachments/0_screenshot.png",
"content_id": "img001@example.com"
}
]
}
}
Inline images¶
Emails with inline images (e.g., pasted screenshots) include:
body_htmlincontent_summary: the full HTML body withcid:referencescontent_idon attachments: matches thecid:reference in the HTML
To render inline images, fetch attachments via /v1/items/{item_id}/attachments (which returns presigned download URLs), then replace cid: references with the corresponding download_url.
Retries¶
2xx: success; no retry.429,5xx, or network/timeout: retried with exponential backoff (see schedule below).- Other
4xx: treated as non-retriable; delivery is marked failed.
Default maximum attempts is 10. Backoff delay (seconds) after attempt n is 5 × 5^(n−1), capped at 24 hours:
| Attempt | Delay before next try |
|---|---|
| 1 | immediate |
| 2 | 5 s |
| 3 | 25 s |
| 4 | ~2 min |
| 5 | ~10 min |
| 6 | ~52 min |
| 7 | ~4.3 h |
| 8 | ~21.7 h |
| 9–10 | 24 h (cap) |
After the last attempt, the delivery is marked failed. See Security for HTTPS and webhook secret handling.