HTTP API
Error codes
Every HTTP status Tapemetric returns, what triggered it, and how to handle it.
Error response shape
json
{
"detail": "invalid api key",
"code": "AUTH_INVALID_KEY",
"request_id": "req_a1b2c3d4e5f6"
}Include the request_id when you contact support — it lets us pull your exact request from our logs.
HTTP status codes
| Status | code | Action |
|---|---|---|
| 400 | VALIDATION_ERROR | Fix payload; don’t retry as-is |
| 401 | AUTH_MISSING | Add auth header |
| 401 | AUTH_INVALID_KEY | Check key not revoked; recreate if needed |
| 401 | AUTH_TOKEN_EXPIRED | Refresh JWT via /v1/auth/login |
| 403 | TENANT_INACTIVE | Contact billing |
| 403 | QUOTA_EXCEEDED | Upgrade plan or wait for reset |
| 403 | SCOPE_DENIED | Key lacks required scope |
| 404 | NOT_FOUND | Resource doesn’t exist for this tenant |
| 409 | CONFLICT | e.g. slug already taken |
| 413 | BATCH_TOO_LARGE | Split into ≤500 event batches |
| 422 | EVENT_SCHEMA_ERROR | A field failed validation — see errors array |
| 429 | RATE_LIMIT | Exponential backoff starting at 1s |
| 500 | SERVER_ERROR | Retry with backoff; open a ticket if it persists |
| 503 | DEGRADED | Ingest briefly down; SDK queues automatically |
Validation errors
json
{
"detail": "validation error",
"code": "VALIDATION_ERROR",
"errors": [
{ "loc": ["events", 0, "event_type"], "msg": "field required" },
{ "loc": ["events", 2, "ts"], "msg": "invalid iso8601 timestamp" }
]
}Retry strategy
For retriable codes (429, 500, 502, 503, 504), the SDK uses exponential backoff starting at 1s, doubling up to 60s, with jitter. Custom HTTP clients should do the same.
typescript
async function retryable<T>(fn: () => Promise<Response>, max = 6): Promise<Response> {
let delay = 1000;
for (let i = 0; i < max; i++) {
const res = await fn();
if (res.ok) return res;
if (![429, 500, 502, 503, 504].includes(res.status)) return res;
await new Promise((r) => setTimeout(r, delay + Math.random() * 500));
delay = Math.min(delay * 2, 60_000);
}
throw new Error('retry budget exhausted');
}Rate limit headers
Every response includes:
X-RateLimit-Limit— requests allowed per minuteX-RateLimit-Remaining— requests left in current windowX-RateLimit-Reset— UTC epoch when the window resets