Skip to main content
API reference

§ 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:

WorkerBase URLAuth
Ingestionhttps://tracklayer-ingestion.sublime.workers.devAPI key (Bearer) for server-side paths; merchant_id in body for /v1/browser/events
APIhttps://tracklayer-api.sublime.workers.devSupabase 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:

FieldNotes
emailTrim and lowercase before sending. Meta receives em as SHA-256 in an array.
phoneInclude country code where possible. Meta strips all non-digits before SHA-256 and sends ph in an array.
genderPrefer m or f; Meta lowercases and hashes the first character as ge.
date_of_birthPrefer YYYYMMDD; ISO dates such as 1990-05-22 are normalized to YYYYMMDD for Meta db.
first_name, last_nameTrim/lowercase; Meta strips punctuation and hashes as fn/ln.
cityTrim/lowercase; Meta removes spaces and punctuation and hashes as ct.
statePrefer canonical region codes: 2-character US state or 3-character non-US subdivision code. Meta sends st.
zip or postal_codePostal code. Meta lowercases, removes spaces/hyphens, hashes as zp.
countryPrefer ISO 3166-1 alpha-2 lowercase (us, de, gb). Meta sends country.
customer_id, external_idsStable customer identifiers. Meta lowercases/trims, hashes, and sends all values as external_id.
client_ip or ipRaw validated IP address for Meta client_ip_address; not hashed.
user_agentRaw browser user agent for Meta client_user_agent; not hashed.
browser_ids.fbp, browser_ids.fbcRaw Meta browser/click IDs; not hashed.
madidMobile advertiser ID. Meta requires the raw lowercased ID; not hashed.
fb_login_id, subscription_id, lead_id, anon_id, ctwa_clidMeta-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 connections
  • POST /v1/platforms — connect a new platform
  • POST /v1/platforms/:id/test — fire a synthetic event
  • DELETE /v1/platforms/:id — disconnect
  • GET /v1/rules — list rules
  • POST /v1/rules — create
  • PATCH /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 status
  • POST /v1/billing/checkout — create Stripe checkout session for an upgrade
  • POST /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's useAiChat hook.

Account

  • GET /v1/account — merchant profile
  • PATCH /v1/account — update name/email/store_platform/store_url/onboarding_step/onboarding_completed
  • GET /v1/api-keys — list keys
  • POST /v1/api-keys — create new key (returns secret once)
  • DELETE /v1/api-keys/:id — revoke

We use essential cookies to keep the site secure and functional. Analytics and third-party tags run only with your consent. See our Cookie Policy.

We use essential cookies to keep the site secure and functional. Analytics and third-party tags run only with your consent. See our Cookie Policy.