Skip to main content
Every status code the /v1 API returns is below, with what causes it and what you do about it.

Error shape

Every error is JSON with an error string:
/ads adds a stable code. /commerce-metrics and the cost-import routes add a stable reason. Branch on code or reason rather than the error text, which we reword.

Status codes

Never treat 503 from /ads or /commerce-metrics as zero spend or zero revenue. These endpoints fail loudly on purpose, so that a read you could not complete never lands in a report as a real number.

Rate limit

Write endpoints spend a second, smaller budget on top of this one: 20 write requests per key per minute, including dry runs. A write therefore needs room in both budgets. The limit counts requests, not rows. One /events request for 1000 rows costs the same as one /workspace request. Every /v1 response carries your current budget, so you do not have to be rejected to find it. The first two headers are present on success and on error responses.

When the limit store is unreachable

Reads and writes behave differently on purpose. A read outage is a wasted query, so a store outage must not take every read down with it. Reads fall back to a standby limit of 30 requests per 60 seconds. That limit is per server, not per key, so your effective budget during an outage is smaller than 100 and is not exactly predictable. Treat X-RateLimit-Degraded: 1 as a signal to slow down. A write that lands twice costs a duplicate conversion rule or a duplicate postback, so writes stop rather than guess. Send an Idempotency-Key on every write, and a retry after a store outage stays safe.

Parameter limits

We clamp a value above the maximum instead of returning 400, so an oversized limit still gives you a page of data.

Pagination

/events and /users page with limit and offset, and both return has_more. Walk a page at a time, adding limit to offset, and stop when has_more is false. Do not stop on a short page instead, because a full range can still end on one. Keep every other parameter identical across the walk, and keep the date range fixed, or the pages will overlap. On /events, total_count is the count for the whole range, so offset cannot walk past it. On /users, offset plus limit must stay at 5000 or less, and a larger window returns 400 rather than a truncated page. Narrow the date range or pass search when you need to go deeper.

Ingest limits

Event ingest runs on a different host, https://ingest.datalyr.com, and has its own limits. The two ingest transports carry different limits. /track takes one server event per request. The SDK batch transport takes an array. The batch limit counts events, not requests. A batch of 50 events costs 50. The /track limit counts requests, which is the same thing there, because each request carries one event. See Ingest API for the full /track contract.

Verify a limit

Send 101 /v1/workspace requests inside one minute. Request 101 returns 429 and the header Retry-After: 60.

Next