Adrails Docs

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:

MethodPathCalled by
GET/api/tracking/scriptYour pages, through a script tag
POST/api/tracking/collectThe 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:

CallerHow it is recognizedWhat happens to its events
A browserIts Origin header is one of the source's allowed domains, or a subdomain of oneRecorded in Adrails, never forwarded
Your serverAuthorization: Bearer atr_server_..., the source's server keyRecorded, 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

CallerLimitWhen it is reached
A browser120 events per minute, per source and per visitor address429 with a Retry-After header, in seconds
Your server, signedNone

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_time must 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.

StatuserrorWhy
400The tracking event is not valid JSON.The body is not JSON.
400The tracking event is invalid.A field fails the schema. details.fieldErrors names it.
403This origin is not allowed for the tracking source.Not signed, and the Origin is not an allowed domain.
404Tracking source not found.No source has this public key.
413The tracking event is too large.The body is over 64,000 bytes.
429Too 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-Origin echoes the request's origin when it is allowed, and is absent otherwise.
  • Access-Control-Allow-Methods: POST, OPTIONS
  • Access-Control-Allow-Headers: authorization, content-type, x-adrails-key
  • Access-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.

On this page