Concepts
Webhook deliveries
Payload
Deliveries are POSTed as JSON { id, event, createdAt, data } with the headers Forms-Event, Forms-Delivery and Forms-Signature.
data is { submission, form: { id, name, version } }. It holds the response with its answers, contact and attribution, and the form and version it was answered on. The delivery log shows data as payload. A form webhook with a posting spec posts the buyer's own format instead, as described below.
Checking the signature
Forms-Signature is t=<unix>,v1=<hex>. The hex is HMAC-SHA256(secret, "<t>.<body>"), keyed with the webhook's signing secret, which starts with whsec_.
Retries
A non-2xx answer or a 10s timeout is retried after 60, 300, 1800, 7200 seconds. After 5 attempts the delivery is failed.
Inactive webhooks get no new deliveries. Every attempt shows in the webhook's delivery log, GET /v1/webhooks/{webhookId}/deliveries. Any delivery can be sent again as a new one with its own retries.
Posting in a buyer's format
A posting spec makes a form webhook post each lead in a buyer's own format. The body holds exactly the spec's keys, in order. With format: "json" it is a flat JSON object of strings, and with "form" it is form-encoded. It carries the spec's extra headers, such as the buyer's API key, plus the usual Forms-Event, Forms-Delivery and Forms-Signature. The signature covers that body.
Each key takes a question's answer, a contact or tracking value, or a constant. Every value is a string. A question that's gone or wasn't answered sends an empty string, and the webhook's postingSpec.warnings names the keys to check. Header values are never returned.
Set one with POST /v1/webhooks/{webhookId}/posting-spec and try it with POST /v1/webhooks/{webhookId}/posting-spec/preview.