Webhooks
A webhook posts to a URL you provide whenever something happens. Use one when you want to react immediately — insert into a database, kick off a job, notify a channel — rather than pull on a schedule.

Setting one up
Settings → Webhooks → Add webhook.
- URL — must be reachable from the internet over HTTPS. Private and local addresses are refused.
- Events — tick which of these to send.
- Secret — optional but recommended. Used to sign every delivery so your endpoint can prove it came from us.
- Headers — anything extra your endpoint needs, such as an API key of its own.
Use Send test event from the row menu to fire a sample at your endpoint and see the real response.
Events
| Event | When |
|---|---|
submission.created | a record is submitted for the first time |
submission.updated | a record’s answers change |
submission.status_changed | approved, returned, or otherwise moved |
submission.deleted | a record is deleted |
form.published | a form is published |
form.archived | a form is archived |
A webhook fires for every form in the organisation. Filter on
data.form_id at your end if you only want some.
What you receive
POST, JSON body, Content-Type: application/json:
{
"event": "submission.created",
"timestamp": "2026-09-03T14:22:07.512Z",
"organization_id": "…",
"data": {
"id": "…",
"form_id": "…",
"form_name": "Equipment Inspection",
"data": { "asset": { "asset_id": "AST-1043", "…": "…" }, "inspected_on": "2026-09-03", "…": "…" },
"submitted_by": "…",
"submitted_at": "2026-09-03T14:22:05.000Z",
"location": { "latitude": -31.95, "longitude": 115.86 }
}
}data.data is the record’s answers keyed by field key — the same shape as the
API returns. submission.updated also carries previous_data;
submission.status_changed carries previous_status and new_status.
Verifying a delivery
When a secret is set, every delivery carries
X-Webhook-Signature: sha256=<hex> — an HMAC-SHA256 of the raw request
body using your secret. Compute it over the exact bytes received, before any
JSON parsing, and compare with a timing-safe function. Reject anything that
does not match.
Retries
Your endpoint should answer 2xx quickly and do its work afterwards. Anything
else, or no answer within the timeout, is retried: after 1 minute, then 5, 15,
1 hour and 4 hours. After the fifth failure the delivery is marked failed and
shown as such under View deliveries, where it can be resent by hand.
Deliveries may occasionally arrive more than once. Use data.id to make your
handling idempotent.
Reaching something that cannot receive a webhook? Ask us at customer.service@firedragontech.com. We will help you get the data where it needs to go.