Error Codes
All errors return a JSON body with an error field:
{
"error": "Missing or invalid API key"
}
HTTP status codes
| Status | Meaning | Common cause |
|---|---|---|
400 Bad Request | Missing or malformed fields | Required field missing, invalid UUID, document too large |
401 Unauthorized | Missing or invalid API key | No Authorization header, expired or revoked key |
403 Forbidden | Key lacks required scope | Using a read-only key to create a mission |
404 Not Found | Resource not found | Mission ID doesn't exist or belongs to another org |
409 Conflict | Duplicate submission | Submitting the same externalRef twice (if deduplication is enabled) |
422 Unprocessable | Document could not be parsed | Corrupted file, unsupported format, or team not found |
429 Too Many Requests | Rate limit exceeded | See rate limits below |
500 Internal Server Error | Server error | Unexpected error — contact support if persistent |
Rate limits
| Endpoint type | Limit |
|---|---|
Read (GET) | 120 requests / minute per key |
Write (POST) | 30 requests / minute per key |
Rate limit headers are included on every response:
| Header | Description |
|---|---|
X-RateLimit-Limit | Your limit for this window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
When rate limited, the response also includes a Retry-After header with the number of seconds to wait.
Retry guidance
429 — Rate limited
Wait for the Retry-After duration before retrying. Use exponential backoff if you're hitting limits repeatedly:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch(url, options);
if (res.status !== 429) return res;
const retryAfter = parseInt(res.headers.get('Retry-After') || '60', 10);
const backoff = retryAfter * 1000 * Math.pow(2, attempt);
await new Promise(r => setTimeout(r, backoff));
}
throw new Error('Max retries exceeded');
}
500 — Server error
Retry with exponential backoff. If errors persist for more than a few minutes, check the Drafted status page or contact support.
4xx errors (except 429)
Do not retry 4xx errors automatically — they indicate a problem with the request itself (bad input, auth failure, etc.) that won't resolve on retry.
Idempotency
Mission creation (POST /missions) is not idempotent by default. Submitting the same request twice creates two missions.
To deduplicate, use the externalRef field with a unique identifier from your system. You can then query GET /missions?externalRef=your-id to check if a mission already exists before creating a new one.