Tracking API
Tiny's public ingest API accepts a bootstrap request first, then event batches for the session created during bootstrap. The browser runtime handles this for you, but the contract is documented here if you need to inspect or reproduce requests directly.
Bootstrap endpoint
Primary endpoint:
POST /api/ingest/v2/:publicKey/bootstrap
Tiny uses bootstrap to validate the source, validate the origin, and create or resume a session for the source.
Events endpoint
Primary endpoint:
POST /api/ingest/v2/:publicKey/events
This endpoint accepts a batch of normalized events for the session created during bootstrap.
Bootstrap request
{
"ingestVersion": 2,
"sdkVersion": "0.2.0",
"anonymousId": "vis_abc123",
"sessionId": null,
"userId": null,
"page": {
"url": "https://app.example.com/dashboard",
"path": "/dashboard",
"title": "Dashboard",
"referrer": "https://app.example.com/login"
},
"context": {
"locale": "en-GB",
"timezone": "Europe/London",
"userAgent": "Mozilla/5.0 ..."
}
}
Bootstrap validation requires:
ingestVersionmust be2sdkVersionmust be presentanonymousIdmust be presentpagemust be present and JSON-compatible
Events request
{
"ingestVersion": 2,
"sdkVersion": "0.2.0",
"batchId": "batch_123",
"sentAt": "2026-04-10T13:45:05.000Z",
"sessionId": "sess_789",
"anonymousId": "vis_abc123",
"userId": "user_42",
"context": {
"locale": "en-GB",
"timezone": "Europe/London",
"userAgent": "Mozilla/5.0 ..."
},
"events": [
{
"id": "evt_1",
"type": "page",
"timestamp": "2026-04-10T13:45:04.000Z",
"anonymousId": "vis_abc123",
"sessionId": "sess_789",
"page": {
"url": "https://app.example.com/dashboard",
"path": "/dashboard",
"title": "Dashboard",
"referrer": null
},
"properties": {},
"context": {}
},
{
"id": "evt_2",
"type": "track",
"name": "report_generated",
"timestamp": "2026-04-10T13:45:05.000Z",
"anonymousId": "vis_abc123",
"sessionId": "sess_789",
"properties": {
"reportType": "weekly"
},
"context": {}
}
]
}
Event validation requires:
ingestVersionmust be2sdkVersion,batchId,sentAt,sessionId, andanonymousIdmust be presenteventsmust be a non-empty array- each event needs an
id,type, and ISOtimestamp trackevents requirenamepageevents require a page payload
Responses
Successful bootstrap response:
{
"ok": true,
"attemptId": "attempt_123",
"ingestVersion": 2,
"sourceId": "src_123",
"sessionId": "sess_789",
"anonymousId": "vis_abc123",
"identifiedUserId": null,
"ingestUrl": "/api/ingest/v2/pk_abc/events"
}
Successful events response:
{
"ok": true,
"attemptId": "attempt_124",
"sourceId": "src_123",
"sessionId": "sess_789",
"accepted": 2,
"duplicates": 0,
"rejected": 0,
"results": [
{
"eventId": "evt_1",
"analyticsEventId": "analytics_evt_1",
"type": "page",
"name": "page_view",
"status": "accepted",
"code": null,
"message": null
}
]
}
Tiny also returns structured failures for:
403source protection checks such as origin mismatch or invalid session for source413payloads that exceed source limits422invalid bootstrap or events payloads, including anissuesarray429request-rate limits
Legacy routes
Legacy ingest routes still exist:
POST /api/ingest/:publicKey/bootstrap
POST /api/ingest/:publicKey/events
Treat them as deprecated compatibility paths. New installs should use the v2 routes only.