Overview
Instead of polling the API every minute to see if something happened, get called: register an address and Aitrack sends a POST when the event occurs. You can also configure these under Settings → Modules → API & Webhooks, or via the API.
The events you can receive are the same ones that trigger automations (entering/leaving an area, ignition, parking, alerts…). An endpoint subscribed to * receives all of them.
Configuring an endpoint
Section titled “Configuring an endpoint”POST /api/webhooks — same authentication as the rest of the API (user session or API key with the X-API-Key header).
| Field | Constraints |
|---|---|
url |
valid URL, https:// only, max 2048 characters |
description |
optional, max 256 characters |
events |
array of strings, at least 1 (use * for all events) |
retry_policy |
none | fixed | exponential (default exponential) |
max_retries |
integer 0–10 (default 5) |
Limit: maximum 100 webhooks per owner.
At creation, a signing secret is generated and shown only once: it’s used to verify the signature of every delivery. On read, the secret is never returned; you can rotate it with POST /api/webhooks/:id/rotate-secret.
curl -X POST https://api.aitrack.it/api/webhooks \ -H "X-API-Key: $AITRACK_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-domain.example.com/webhooks/aitrack", "description": "Fleet sync", "events": ["geofence_enter", "geofence_exit"], "retry_policy": "exponential", "max_retries": 5 }'const res = await fetch('https://api.aitrack.it/api/webhooks', { method: 'POST', headers: { 'X-API-Key': process.env.AITRACK_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ url: 'https://your-domain.example.com/webhooks/aitrack', description: 'Fleet sync', events: ['geofence_enter', 'geofence_exit'], retry_policy: 'exponential', max_retries: 5, }),});const { webhook } = await res.json();console.log(webhook); // the "secret" field only comes back in THIS responseres = requests.post( "https://api.aitrack.it/api/webhooks", headers={"X-API-Key": api_key, "Content-Type": "application/json"}, json={ "url": "https://your-domain.example.com/webhooks/aitrack", "description": "Fleet sync", "events": ["geofence_enter", "geofence_exit"], "retry_policy": "exponential", "max_retries": 5, }, timeout=10,)webhook = res.json()["webhook"] # "secret" only comes back in this responseManagement endpoints
Section titled “Management endpoints”| Method | Path | Description |
|---|---|---|
POST |
/api/webhooks |
Create an endpoint |
GET |
/api/webhooks |
List the owner’s endpoints |
GET |
/api/webhooks/:id |
Detail (without the secret) |
PUT |
/api/webhooks/:id |
Update (the URL is re-validated) |
DELETE |
/api/webhooks/:id |
Delete |
POST |
/api/webhooks/:id/test |
Send a ping event to that endpoint only |
POST |
/api/webhooks/:id/rotate-secret |
Rotate the signing secret |
GET |
/api/webhooks/:id/deliveries |
Delivery history, paginated |
GET |
/api/webhooks/metrics/summary |
24h metrics (success rate, p95…) |
GET |
/api/webhooks/dead-letter/list |
Exhausted deliveries (dead-letter) |
POST |
/api/webhooks/deliveries/:deliveryId/replay |
Requeue a failed or exhausted delivery |
Every endpoint is filtered by owner: you never see or touch anyone else’s webhooks.
Payload
Section titled “Payload”Every delivered event has the same body:
{ "id": "evt_9f2c1a4b7e6d4f0a9b3c2d1e0f8a7b6c", "type": "geofence_enter", "created_at": "2026-07-14T09:00:00.000Z", "data": { }}data’s shape depends on the event type. id is stable per event: if the same id arrives twice (a retry), discard it — see Delivery & retries.