Response Codes
HTTP status codes returned by the Tournament Suite API and how to handle them.
The Tournament Suite API uses standard HTTP status codes to indicate whether a request succeeded or failed.
Success codes
| Code | Meaning | When it occurs |
|---|---|---|
200 OK | Request succeeded | GET, PATCH, DELETE, and most POST operations |
201 Created | Resource created | POST that creates a new resource |
All successful responses share a consistent JSON envelope:
{
"success": true,
"data": { "id": "550e8400-e29b-41d4-a716-446655440000" },
"message": "Resource updated successfully"
}
data holds the resource (or resources) returned by the endpoint; message is a short, human-readable summary of what happened.
Client error codes
| Code | Meaning | Common causes |
|---|---|---|
400 Bad Request | Invalid request body or parameters | Missing required fields, type errors |
401 Unauthorized | Authentication failed | Missing or invalid API key / expired token |
403 Forbidden | Authenticated but not authorized | API key missing a required scope, accessing another project's data |
404 Not Found | Resource does not exist | Wrong ID, deleted resource |
409 Conflict | State conflict | Duplicate registration, resource already in that state |
422 Unprocessable Entity | Validation failed | Business rule violation (e.g. tournament already started) |
429 Too Many Requests | Rate limit exceeded | Check X-RateLimit-* and Retry-After headers and back off |
Scope-based 403s
Every API key is issued with a fixed set of scopes (for example read:tournaments, read:matches, read:teams). If a request targets an endpoint that needs a scope your key wasn't granted, the API returns a 403 Forbidden with a message naming the missing scope(s), such as:
{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "API key is missing required scope(s): read:tournaments",
"timestamp": "2026-06-01T10:00:00.000Z",
"path": "/api/v1/tournaments"
}
}
Check the scopes attached to your API key in the developer portal and reissue a key with the scopes your integration needs.
Server error codes
| Code | Meaning | What to do |
|---|---|---|
500 Internal Server Error | Unexpected server error | Retry with exponential backoff; contact support if persistent |
503 Service Unavailable | Temporary outage or maintenance | Retry with exponential backoff |
Error response format
All error responses follow a consistent JSON envelope:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Tournament with ID '550e8400' was not found.",
"timestamp": "2026-06-01T10:00:00.000Z",
"path": "/api/v1/tournaments/550e8400"
},
"metadata": {
"timestamp": "2026-06-01T10:00:00.000Z",
"path": "/api/v1/tournaments/550e8400",
"method": "GET",
"statusCode": 404,
"version": "v1",
"requestId": "req-abc123def456"
}
}
error.code is a fixed status-based code (BAD_REQUEST, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, CONFLICT, VALIDATION_ERROR, and similar) — it does not vary per resource type. The top-level metadata object is attached alongside error and includes a requestId you can quote when contacting support.
Handling rate limits
Every response includes X-RateLimit-Limit and X-RateLimit-Remaining headers. When you receive a 429, the response also includes a Retry-After header giving the number of seconds to wait before your next request:
const response = await fetch(url, { headers });
if (response.status === 429) {
const retryAfterSeconds = Number(response.headers.get('Retry-After'));
const waitMs = retryAfterSeconds * 1000;
await new Promise(resolve => setTimeout(resolve, waitMs));
// retry
}Was this helpful?
