incident is always an object, Send test will break your parser. If you treat every POST as a new outage, a retry or an escalation page will duplicate work.
This is the body when the channel has no Handlebars template. Templated channels still interpolate from these fields. check may be absent; treat check.* as optional.
Headers
Every delivery includes these headers. VerifyX-Tallwatch-Signature before you parse or act on the body.
X-Tallwatch-Event matches the JSON event field. X-Tallwatch-Timestamp is the same unix seconds as t in the signature header.
Example
eventis what happened (incident.opened,incident.acknowledged,incident.resolved,incident.flapping, ortest).occurred_atis when the event happened (ISO 8601).orgis the workspace that owns the monitor (id,name,slug).monitoris the check involved (id,name,type, andurlwhen the check has one).incidentis the outage record, ornullon a test send.idis the stable key;statusisopenin this example;failing_regionslists region labels that voted down.checkis extra probe detail when Tallwatch has it. Here it isnull. It may also be omitted. Never requirecheck.*.
Incident identity
incident.id is stable across open / ack / resolve for one outage. Open a ticket (or update a row) keyed on that id, then on incident.acknowledged and incident.resolved update the same record instead of creating a second one.
Escalation pages reuse incident.opened. A later notify step is another POST with the same event name and the same incident.id, not a different event type. Idempotency on incident.id (and treating a second incident.opened as a no-op if you already opened the ticket) keeps one ticket per outage.
Send test sets event to test and incident to null. Your handler must accept a body with no incident. Do not write an incident row for test.
Retries
Make your receiver idempotent. Tallwatch can retry the same POST after a timeout. If the first attempt created a ticket and then timed out, the retry is the same event and the sameincident.id. Returning 2xx quickly (or 202 and processing asynchronously) avoids the timeout path; idempotency covers the case where the timeout still happens.
See to verify the POST, to scaffold the endpoint, and if this JSON is not the shape your receiver wants.