TANITARDevelopers
Webhooks

The delivery request

What Tanitar sends to your endpoint: the headers, the event envelope, and how your receiver should answer.

Each delivery is one HTTPS POST to your endpoint URL. The body is the event envelope as JSON; the headers identify, sign and describe it.

Example

POST /your/webhook/endpoint HTTP/1.1
Content-Type: application/json
User-Agent: Tanitar-Webhooks/1
webhook-id: whd_3f1c2a9e-8b7d-4c1a-9e2f-5d6b7a8c9d0e
webhook-timestamp: 1800000000
webhook-signature: v1,fqM1zvDrPfiCYH4CqlC1k+5CYE9qx8TG3bFYaIop8Bc=
tanitar-event-type: tournament.tournament.started
tanitar-schema-version: 1
tanitar-delivery-attempt: 1

{"messageId":"4b8f6c1e-2d3a-4e5f-8a9b-0c1d2e3f4a5b","kind":"event","type":"tournament.tournament.started","schemaVersion":1,"occurredAt":"2027-01-15T08:00:00.000Z","producer":"tournament-management-service","accountId":"acc_example","correlationId":"req_example","data":{"tournamentId":"trn_example","organizationId":"org_example","revision":4,"startedAt":"2027-01-15T08:00:00.000Z"}}

This request is signed with the example secret whsec_placeholder_example_webhooks_signing_secret, the same one used on every page of the event catalog, so you can check your verifier against it byte for byte.

Headers

HeaderAlwaysValue
webhook-idYesThe delivery id (whd_…). Identical on every retry and replay of this delivery.
webhook-timestampYesUnix time in seconds at which this attempt was signed.
webhook-signatureYesOne or more space-separated v1,<base64> signatures. See Verifying signatures.
tanitar-event-typeYesThe envelope's type, for routing before you parse the body.
tanitar-schema-versionYesThe envelope's schemaVersion.
tanitar-delivery-attemptYesThe attempt number within the current cycle, starting at 1. It restarts at 1 on a replay.
tanitar-replayReplays onlytrue when an administrator replayed this delivery.
Content-TypeYesapplication/json
User-AgentYesTanitar-Webhooks/1

webhook-id, webhook-timestamp and webhook-signature follow the Standard Webhooks convention, so a Standard Webhooks verification library accepts Tanitar deliveries once it is given the key as Verifying signatures describes.

The envelope

The body is the same envelope Tanitar uses for all its events, exactly as the producing service published it. Your subscription decides which type values you receive; the shape of data for each type is on its event catalog page.

FieldRequiredTypeMeaning
messageIdYesstringUnique id of the event. Stable across every delivery of it.
kindYes"event"Always event for a webhook delivery.
typeYesstringEvent type, dot-separated, for example shop.order.settled.
schemaVersionYesintegerMajor version of the data contract for this type.
occurredAtYesstring (date-time)When the event happened, in UTC.
producerYesstringThe Tanitar service that published it, for example reward-management-service.
accountIdYes on webhooksstringYour organization's account id.
correlationIdYesstringCorrelates the event with the request or workflow that caused it.
dataYesobjectThe event payload.
subjectNoobjectThe resource the event is about: type, id, and an optional integer revision.
principalNoobjectWho caused it: kind, id, and optionally role and serviceId.
causationIdNostringThe id of the message that directly caused this one.
idempotencyKeyNostringThe idempotency key of the producing operation, when it had one.

No other top-level fields are added.

How to answer

  • Verify first. Check the signature against the raw body before parsing or acting on it.
  • Answer 2xx quickly. Any 2xx status settles the attempt as delivered. Acknowledge as soon as the event is stored, and do the work asynchronously.
  • Stay inside the timeout. Tanitar waits 10 seconds for a response by default. A slower answer is a failed attempt even if your receiver processed the event.
  • Do not redirect. Tanitar does not follow redirects; any 3xx is a failed attempt.
  • Answer 410 Gone only to stop. A 410 settles the delivery as dead at once, without further retries. Use it when the endpoint is being decommissioned.

Any other status, a timeout, a TLS failure or a network error counts as a failed attempt and is retried. Tanitar stores the status code, the duration and at most the first 1 KiB of your response body for each attempt, so keep error bodies short and free of secrets.

Deduplicate on webhook-id

Delivery is at least once: a retry after a timeout, or a replay, can bring the same delivery again. webhook-id is the same on every attempt and every replay of a delivery, so record the ids you have processed and skip a repeat. If you register several endpoints for the same event, each endpoint receives its own delivery with its own webhook-id; use messageId to recognise the same event across them.

Deliveries are not ordered. Two events can arrive in the opposite order to occurredAt, notably when one of them was retried. Order by occurredAt and by the revision fields in data or subject.

The delivery log

The dashboard shows each delivery with its status (pending, delivered or dead), every attempt (status code, error class, duration, response excerpt) and, for a dead delivery, its reason. It reads GET /dashboard/v1/webhooks/deliveries, which filters by endpointId, status, eventType and a from/to creation window, and pages with page and limit (default 20, maximum 100), returning { items, page, limit, total }. One delivery is GET /dashboard/v1/webhooks/deliveries/:deliveryId. Settled deliveries are kept for 30 days.

On this page