§ 04
API reference
TrackLayer REST API for ingesting events, managing platforms, querying analytics, and administering routing rules. Two base URLs — the public ingestion worker for browser+server events, and the authenticated API for dashboard operations.
API reference
TrackLayer exposes two Cloudflare Workers:
| Worker | Base URL | Auth |
|---|---|---|
| Ingestion | https://tracklayer-ingestion.sublime.workers.dev | API key (Bearer) for server-side paths; merchant_id in body for /v1/browser/events |
| API | https://tracklayer-api.sublime.workers.dev | Supabase JWT (Bearer) |
All endpoints return JSON, including errors.
Authentication
Ingestion (server-side)
curl -X POST https://tracklayer-ingestion.sublime.workers.dev/v1/events \
-H "Authorization: Bearer tl_live_XXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{...}'Generate API keys in Settings → API Keys. Keys show once on creation and cannot be retrieved after. Copy immediately, store securely (Cloudflare Secrets, Vault, etc.).
API (dashboard operations)
All /v1/* paths on the API worker require a Supabase session JWT:
curl https://tracklayer-api.sublime.workers.dev/v1/events \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Your JWT is issued by supabase.auth.signInWithPassword and refreshed automatically by the dashboard's Supabase client.
Ingestion endpoints
POST /v1/events
Server-side event ingestion. Requires API key + body with valid trackEventSchema.
{
"event_id": "order-12345",
"event_name": "purchase",
"event_time": 1776678000,
"merchant_id": "5353bbf0-07ad-4636-98c6-64861af1b8c9",
"source": "server",
"user_data": {
"email": "buyer@example.com",
"phone": "+15551234567",
"first_name": "Ada",
"last_name": "Lovelace",
"city": "San Francisco",
"state": "ca",
"zip": "94103",
"country": "us",
"customer_id": "cust_123",
"browser_ids": { "fbp": "fb.1...", "fbc": "fb.1..." }
},
"value": 129.99,
"currency": "USD",
"order_id": "12345",
"items": [{ "id": "SKU-A", "quantity": 1, "price": 129.99 }]
}Response:
{ "success": true, "event_id": "order-12345" }Returns 202 on success (event queued, not yet delivered). 400 on schema validation failure. 401 on invalid API key. 409 on duplicate event_id within the 24h dedup window.
user_data contract
TrackLayer accepts the following identity fields and normalizes/hashes them per destination before delivery:
| Field | Notes |
|---|---|
email | Trim and lowercase before sending. Meta receives em as SHA-256 in an array. |
phone | Include country code where possible. Meta strips all non-digits before SHA-256 and sends ph in an array. |
gender | Prefer m or f; Meta lowercases and hashes the first character as ge. |
date_of_birth | Prefer YYYYMMDD; ISO dates such as 1990-05-22 are normalized to YYYYMMDD for Meta db. |
first_name, last_name | Trim/lowercase; Meta strips punctuation and hashes as fn/ln. |
city | Trim/lowercase; Meta removes spaces and punctuation and hashes as ct. |
state | Prefer canonical region codes: 2-character US state or 3-character non-US subdivision code. Meta sends st. |
zip or postal_code | Postal code. Meta lowercases, removes spaces/hyphens, hashes as zp. |
country | Prefer ISO 3166-1 alpha-2 lowercase (us, de, gb). Meta sends country. |
customer_id, external_ids | Stable customer identifiers. Meta lowercases/trims, hashes, and sends all values as external_id. |
client_ip or ip | Raw validated IP address for Meta client_ip_address; not hashed. |
user_agent | Raw browser user agent for Meta client_user_agent; not hashed. |
browser_ids.fbp, browser_ids.fbc | Raw Meta browser/click IDs; not hashed. |
madid | Mobile advertiser ID. Meta requires the raw lowercased ID; not hashed. |
fb_login_id, subscription_id, lead_id, anon_id, ctwa_clid | Meta-specific raw IDs; not hashed. |
Empty strings, nulls, and whitespace-only values are omitted. SDKs should send canonical state and country codes where possible; TrackLayer includes common US state and country-name normalization only as a compatibility fallback.
POST /v1/browser/events
Public browser-pixel endpoint. No API key — merchant_id comes from the body. Rate-limited per (merchant_id, client IP) at 30 events / 60s.
Same schema as /v1/events but with no Authorization header. Bot detection still applies (events from headless browsers without a real User-Agent are dropped).
GET /v1/pixel.js
The 3.3 KB browser SDK. Served with Cache-Control: public, max-age=300, s-maxage=3600. See Installation for usage.
Analytics endpoints
All require Supabase JWT.
GET /v1/analytics/overview?range=7d
Returns aggregate KPIs for the ranges 24h, 7d, 30d, 90d.
{
"range": "7d",
"events_24h": 12471,
"delivery_rate": 99.2,
"health_score": 94,
"active_platforms": 8,
"revenue_tracked": 284910.50,
"avg_latency_ms": 127,
"deltas": { "events_24h": 18.4, ... }
}GET /v1/analytics/volume?range=7d
Daily event counts for the date range.
GET /v1/analytics/coverage?range=7d
32×12 matrix of event-name × platform delivery counts.
GET /v1/analytics/quality?range=7d
Match Quality Score + per-field completeness + top 10 validation issues.
GET /v1/analytics/funnel?range=30d
Funnel stages with drop-off counts.
GET /v1/analytics/revenue-attribution?range=30d
Per-platform first-touch revenue + order counts.
Event endpoints
GET /v1/events?limit=50&offset=0
List events with filters: platform, status, event_name, source, start, end, search, limit, offset, orderBy, orderDirection.
GET /v1/events/:id
Single event + its deliveries (one row per platform targeted).
POST /v1/events/:id/replay
Re-enqueue the event through the full consumer fan-out pipeline. Returns {ok, replayed_at, event_id} where event_id is the new suffix-appended ID of the replayed event.
POST /v1/events/:id/forward
Body: { platforms: string[] }. Same as replay but the consumer only fans out to the specified platform subset.
POST /v1/events/:id/retry-failed
Same as forward but the platform list is auto-derived from deliveries currently in FAILED / ERROR / RETRY state.
Platforms + Rules
See Platforms and Rules for the full CRUD.
GET /v1/platforms— list configured connectionsPOST /v1/platforms— connect a new platformPOST /v1/platforms/:id/test— fire a synthetic eventDELETE /v1/platforms/:id— disconnectGET /v1/rules— list rulesPOST /v1/rules— createPATCH /v1/rules/:id— update (toggle enabled, swap platforms)DELETE /v1/rules/:id— delete
Billing
GET /v1/billing/plans— plan catalog (public)GET /v1/billing/usage— current period usage + plan + Stripe statusPOST /v1/billing/checkout— create Stripe checkout session for an upgradePOST /v1/billing/portal— open Stripe customer portal for payment/cancellation
AI chat
POST /v1/ai/chat— SSE-streaming Claude + tool use. Consumed by the dashboard'suseAiChathook.
Account
GET /v1/account— merchant profilePATCH /v1/account— update name/email/store_platform/store_url/onboarding_step/onboarding_completedGET /v1/api-keys— list keysPOST /v1/api-keys— create new key (returns secret once)DELETE /v1/api-keys/:id— revoke