Skip to main content

Error Codes

All errors return a JSON body with an error field:

{
"error": "Missing or invalid API key"
}

HTTP status codes

StatusMeaningCommon cause
400 Bad RequestMissing or malformed fieldsRequired field missing, invalid UUID, document too large
401 UnauthorizedMissing or invalid API keyNo Authorization header, expired or revoked key
403 ForbiddenKey lacks required scopeUsing a read-only key to create a mission
404 Not FoundResource not foundMission ID doesn't exist or belongs to another org
409 ConflictDuplicate submissionSubmitting the same externalRef twice (if deduplication is enabled)
422 UnprocessableDocument could not be parsedCorrupted file, unsupported format, or team not found
429 Too Many RequestsRate limit exceededSee rate limits below
500 Internal Server ErrorServer errorUnexpected error — contact support if persistent

Rate limits

Endpoint typeLimit
Read (GET)120 requests / minute per key
Write (POST)30 requests / minute per key

Rate limit headers are included on every response:

HeaderDescription
X-RateLimit-LimitYour limit for this window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix 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.