API reference
The Tracking API, the one Adrails API meant for your own site and server. Authentication, limits, errors and CORS.
The Tracking API has two endpoints:
| Method | Path | Called by |
|---|---|---|
GET | /api/tracking/script | Your pages, through a script tag |
POST | /api/tracking/collect | The script, your pages and your server |
Every other route serves the app itself and is not part of this API.
Download the OpenAPI 3.1 document to import into an API client or generate code from. A test in the Adrails repository checks it against the code that serves these endpoints: every field, limit, status and error.
Base URL
Requests go to the address of Adrails, the one in your snippet in Settings > Tracking, such as https://adrails.ai.
Authentication
A call names its tracking source with the public key, atr_..., in the key query parameter or the x-adrails-key header. The public key identifies the source; it proves nothing, since it is in every page of your site.
A call is then accepted in one of two ways:
| Caller | How it is recognized | What happens to its events |
|---|---|---|
| A browser | Its Origin header is one of the source's allowed domains, or a subdomain of one | Recorded in Adrails, never forwarded |
| Your server | Authorization: Bearer atr_server_..., the source's server key | Recorded, and forwarded to Meta and Google Ads when set up, within the source's limits |
A call with neither is refused with 403. The server key is shown to owners and administrators in Settings > Tracking. See Set up tracking.
Rate limits
| Caller | Limit | When it is reached |
|---|---|---|
| A browser | 120 events per minute, per source and per visitor address | 429 with a Retry-After header, in seconds |
| Your server, signed | None |
The limit on what reaches the ad platforms is separate: a largest value per event and a number of events per day. Events past it are still accepted, and held back. See Limits.
Requests and responses
- Send
Content-Type: application/json. The body is at most 64,000 bytes. - Text fields are trimmed. An empty string is refused: leave the field out or send
null. - Unknown fields are ignored.
event_timemust be within the last 7 days and at most 5 minutes ahead.
A recorded event is answered with 202; an event_id the source already recorded with 200 and "duplicate": true. Neither says whether the event reached Meta or Google Ads: Settings > Tracking does.
Errors
Errors are JSON with an error sentence. A schema error adds details, the fields that failed.
| Status | error | Why |
|---|---|---|
400 | The tracking event is not valid JSON. | The body is not JSON. |
400 | The tracking event is invalid. | A field fails the schema. details.fieldErrors names it. |
403 | This origin is not allowed for the tracking source. | Not signed, and the Origin is not an allowed domain. |
404 | Tracking source not found. | No source has this public key. |
413 | The tracking event is too large. | The body is over 64,000 bytes. |
429 | Too many tracking events from this visitor. | A browser caller passed 120 events in a minute. |
{
"details": {
"formErrors": [],
"fieldErrors": {
"event_id": ["String must contain at least 8 character(s)"]
}
},
"error": "The tracking event is invalid."
}CORS
The collect endpoint answers browsers from your allowed domains:
Access-Control-Allow-Originechoes the request's origin when it is allowed, and is absent otherwise.Access-Control-Allow-Methods: POST, OPTIONSAccess-Control-Allow-Headers: authorization, content-type, x-adrails-keyAccess-Control-Max-Age: 86400
The 404 answer carries no CORS headers, so a page cannot read it. The script itself is served with Cross-Origin-Resource-Policy: cross-origin, so any page can load it.
Send conversions to Meta and Google Ads
Send the events your server signs to a Meta dataset and a Google Ads conversion action, within a value limit and a daily limit.
Record an event POST
POST /api/tracking/collect records a page view, lead or sale for your tracking source, and forwards signed events to Meta and Google Ads.
