Skip to main content
POST https://api.craftkit.dev/v1/hooks/:token
Triggers a render from any external system that can POST JSON. The webhook URL and HMAC secret are auto-generated when a template is created. The body is the variable data, flat — no { data: … } wrapper. Inbound renders share the rendering pipeline with POST /v1/templates/:slug/render: same Zod validation, versioning, dashboard row, and outgoing webhooks.

Authorization

Inbound webhooks are not authenticated with a project API key. The per-template token in the URL identifies the template; an optional HMAC signature proves the payload’s integrity.
x-craftkit-signature
string
Optional. Hex-encoded HMAC-SHA256 of the raw request body, keyed by the template’s inbound secret. When present it is verified; when absent the request is accepted (toggle enforcement per template in the dashboard for production traffic).

Path parameters

token
string
required
The per-template inbound token from the Use this template → Inbound webhook panel. Identifies and authenticates the target template.

Body

The body is the flat variable data — the manifest keys for the target template, with no envelope. Scalars nest by dot-path; loops are keyed by their dot-free top-level key. Keys absent from the manifest are stripped. Invalid payloads return 400 invalid_input_data with the offending fields in issues.fieldErrors.
(manifest keys)
object
required

Response

202 when a render is queued.
id
string
Render id (UUIDv7).
status
string
Always queued on accept.
pollUrl
string
GET this with your project bearer token to poll the render.

Errors

StatuscodeMeaning
400invalid_jsonBody is not valid JSON.
400invalid_input_dataBody did not match the template manifest (issues included).
401invalid_signaturex-craftkit-signature was present but did not match.
404invalid_tokenNo template matches this inbound token.
409no_published_versionTemplate has no published version yet.
503queue_unavailableRender queue is temporarily unreachable — retry.
cURL
BODY='{"customer":{"name":"Acme Corp"},"items":[{"name":"Widget","qty":5,"price":9.99}],"total":49.95}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$CRAFTKIT_INBOUND_SECRET" -hex | awk '{print $2}')
curl -X POST "https://api.craftkit.dev/v1/hooks/$CRAFTKIT_INBOUND_TOKEN" \
  -H "x-craftkit-signature: $SIG" \
  -H "Content-Type: application/json" \
  -d "$BODY"
202
{
  "id": "0193c2c3-...",
  "status": "queued",
  "pollUrl": "https://api.craftkit.dev/v1/renders/0193c2c3-..."
}