TANITARDevelopers
Getting started

Errors

The shared error envelope, its categories and status codes, the access error codes, and request correlation.

Every Tanitar API reports errors in the same JSON envelope, so one error handler covers all of them.

The error envelope

{
  "success": false,
  "statusCode": 409,
  "responseType": "CONFLICT",
  "errorCode": "ACCESS_REPLAYED",
  "message": "Conflict",
  "data": null,
  "requestId": "3b9e7a52-1c4d-4f0e-8a6b-5d2c9e1f7a04",
  "timestamp": "2026-09-30T11:20:37.412Z"
}
FieldTypeMeaning
successfalseAlways false on an error.
statusCodenumberThe HTTP status, repeated in the body.
responseTypestringThe error category. It always agrees with statusCode (see below).
errorCodestring, optionalA stable, machine-readable code such as ACCESS_SCOPE_DENIED or TOURNAMENT_NOT_FOUND. Present whenever the failure is a typed refusal; absent when it is not.
messagestringA human-readable description. It can change; do not parse it.
datanullAlways null on an error.
requestIdstringThe identifier of this request, for correlation (see below).
timestampstringWhen the error was produced, in ISO 8601 UTC.
detailsarray, optionalField-level validation messages, present on validation failures.

The Identity API also returns a code field beside errorCode, carrying a stable code on every error body. Prefer errorCode where both are present.

Categories and status codes

responseTypeStatusTypical cause
BAD_REQUEST400Malformed JSON, failed validation, a missing or invalid Idempotency-Key.
UNAUTHORIZED401Missing or invalid credential.
FORBIDDEN403The credential is valid but not allowed to do this.
NOT_FOUND404The route or the resource does not exist.
CONFLICT409The request conflicts with current state: a duplicate, a stale revision, an idempotency conflict.
UNPROCESSABLE_ENTITY422The request is well formed but breaks a domain rule, for example an unsupported value.
TOO_MANY_REQUESTS429A rate limit. See rate limits.
INTERNAL_SERVER_ERROR500, 502An unexpected failure (500), or an upstream provider failure (502).
SERVICE_UNAVAILABLE503A dependency Tanitar needs to decide the request is unavailable. Retry later.

A few behaviours to rely on:

  • Validation failures answer 400 with message "Validation failed" and the individual field messages in details.
  • Unexpected failures answer 500 with the fixed message "Internal Server Error". Internal detail never appears in a response; quote the requestId to Tanitar support instead.
  • Branch on errorCode, and fall back to responseType when there is no errorCode. Never branch on message.

Successful responses are not wrapped the same way on every API: some return { "success": true, "data": …, "responseType": "SUCCESS" }, others return the resource directly. The guides show the success body of each route.

Access error codes

These codes come from the checks every API applies before a request reaches its domain logic: authentication, scopes, rate limits, ownership and idempotency. They mean the same thing on every API.

errorCodeStatusMeaningWhat to do
ACCESS_CREDENTIAL_INVALID401The credential is missing, malformed, unknown, expired or revoked, or is the wrong kind for this route.Check the key and the header. Do not retry unchanged.
ACCESS_ACCOUNT_DISABLED403Your account is not active (for example, suspended).Contact Tanitar.
ACCESS_SCOPE_DENIED403The key does not carry the scope this route requires.Use a key with the scope. See scopes.
ACCESS_ENTITLEMENT_DENIED403The key carries the scope, but your plan no longer includes it.Change plan or use a different route.
ACCESS_RESOURCE_FORBIDDEN403The resource does not belong to your account or organization. Routes that check ownership also answer this for a resource that does not exist, so they never reveal whether an identifier is in use elsewhere.Check the identifier.
ACCESS_IDEMPOTENCY_REQUIRED400The route requires an Idempotency-Key header and none was sent.Add the header.
ACCESS_IDEMPOTENCY_INVALID400The Idempotency-Key is not 1–256 characters from A–Z a–z 0–9 . _ : -.Fix the key.
ACCESS_IDEMPOTENCY_IN_PROGRESS409An earlier request with the same key is still running.Wait, then retry with the same key.
ACCESS_REPLAYED409The key was already used for a different request.Use a new key for the new request.
ACCESS_RATE_LIMITED429The key exceeded its plan's limit for this rate class.Back off exponentially and retry.
ACCESS_STATE_UNAVAILABLE503Tanitar could not reach state it needs to decide the request, and refused rather than guess.Back off and retry; for a mutation, reuse the same Idempotency-Key.

Access refusals always carry the category's generic message ("Unauthorized", "Forbidden", and so on). They never reveal key, plan or infrastructure detail.

Domain errors use codes named after their area, such as TOURNAMENT_NOT_FOUND or LEADERBOARD_PERIOD_UNSUPPORTED, and are listed in the guide for each capability.

Tenant storage error codes

Your data lives in storage Tanitar resolves per account. When that resolution fails, the API refuses the request instead of reading or writing anywhere else, so none of these codes means your request partly happened. See multi-tenancy.

errorCodeStatusMeaningWhat to do
TENANT_DATABASE_UNAVAILABLE503Your database could not be reached.Back off and retry; for a mutation, reuse the same Idempotency-Key.
TENANT_CONNECTION_UNHEALTHY503The connection to your database is not healthy.Back off and retry, as above.
TENANT_CONTEXT_UNAVAILABLE503The routing state that says where your data lives could not be read.Back off and retry, as above.
TENANT_POOL_CAPACITY503Connection capacity for your account is exhausted.Retry after a longer pause. Contact Tanitar if it persists.
TENANT_SCHEMA_INCOMPATIBLE503Your database is mid-upgrade and not ready for this request.Retry later. Contact Tanitar if it persists.
TENANT_ACCESS_DISABLED403Your account is not in a state that permits data access.Contact Tanitar. Do not retry unchanged.
TENANT_ROUTING_MISMATCH403The request does not match your account's routing state.Contact Tanitar. Do not retry unchanged.

Correlating requests

Every success and error response carries an x-request-id header. Every error body also carries the same value in requestId.

You can supply your own: send an X-Request-Id header of 1 to 128 characters from A–Z a–z 0–9 . _ : -, and Tanitar uses it for the request and echoes it back. If you send none, or one that does not match, Tanitar generates a UUID.

curl "$REWARD_API_URL/v1/currencies" \
  -H "Authorization: Bearer $TANITAR_API_KEY" \
  -H "X-Request-Id: checkout-7f3a-attempt-1" -i

Log the request id with every call you make. When you contact Tanitar about a failed request, the request id is the fastest way to find it.

On this page