Skip to content

Delivery & retries

We only accept https:// URLs, never internal or private addresses — the same protection that stops a webhook from becoming a probe into Aitrack’s own network (see “SSRF protection” below).

  • Timeout: 10 seconds.
  • Redirects: none followed (0 redirects allowed).
  • Content-Type: application/json.
  • Deliveries to the same endpoint are serialized: they never arrive in parallel, so they don’t hammer your server.

If your endpoint doesn’t respond 2xx, the delivery is retried according to the retry_policy chosen in configuration:

Policy Behavior
exponential (default) intervals double — 2, 4, 8, 16 minutes — up to max_retries attempts
fixed every 5 minutes, up to max_retries attempts
none no retry: a failure goes straight to dead-letter

max_retries is configurable 0–10 (default 5). Once attempts are exhausted, the delivery ends up in dead-letter and you can replay it manually.

GET /api/webhooks/dead-letter/list lists exhausted deliveries (status exhausted).

POST /api/webhooks/deliveries/:deliveryId/replay requeues a delivery in failed or exhausted status for an immediate new attempt.

pending → delivered (2xx response) or failed (awaiting retry) → exhausted (retries exhausted, or retry_policy: none).

The webhook URL is chosen by you: without defenses it would be a vector toward internal services or cloud metadata endpoints. Validation is applied twice:

  1. At create/update time — rejects non-https URLs, loopback hosts, private literal IPs (400 WEBHOOK_URL_INVALID).
  2. At delivery time — re-validated with DNS resolution, to cover DNS rebinding (a hostname can resolve to a private IP only at send time, after being validated harmlessly at creation). If the URL isn’t safe, the delivery is marked failed without any request being sent.

No redirect is ever followed, for the same reason: a public endpoint could redirect to an internal host after validation.

event_type values correspond to the automation trigger types configurable in Aitrack (entering/leaving an area, parking, ignition, tamper alert, RFID…), plus ping for manually testing an endpoint. An endpoint subscribed to * receives every event, present and future, without needing to update the list each time a new type ships.

An endpoint only receives an event if it’s active and its events list contains that type — or the * wildcard.