Errors & Rate Limits
The Armox Public API uses standard HTTP status codes and a consistent JSON error shape.
Error Response Format
{ "error": "Human-readable message" }
Examples:
{ "error": "Invalid API key" }
{ "error": "Insufficient credits. Required 1000, available 200" }
Error Codes
| Code | Meaning | Typical Cause |
|---|---|---|
400 | Bad Request | Invalid payload, missing required field, invalid model |
401 | Unauthorized | Missing or invalid Bearer API key |
402 | Payment Required | Insufficient credits |
403 | Forbidden | Plan/access restrictions |
404 | Not Found | Resource/job/app not found |
409 | Conflict | Job cannot be cancelled in current state |
429 | Too Many Requests | Per-key rate limit exceeded |
500 | Internal Server Error | Unexpected backend failure |
Rate Limits
Rate limiting is enforced per API key using a rolling 60-second window.
Every successful authenticated response includes:
X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-Reset
If limit is exceeded, API returns:
- status
429 - error body
{ "error": "Rate limit exceeded" } Retry-After: 60header
Handling 429 Responses
Recommended strategy:
- read
Retry-Afterheader - wait before retrying
- use exponential backoff with jitter for repeated 429s
- avoid synchronized retries across workers
Common trigger:
- Polling
GET /api/v1/jobs/:idtoo aggressively (for example every 2-4 seconds) on low-RPM API keys. - Safer default is polling every
10-15seconds and honoringRetry-After.
JavaScript Retry Example
async function requestWithRetry(url, options, retries = 3) {
for (let attempt = 0; attempt <= retries; attempt += 1) {
const response = await fetch(url, options);
if (response.status !== 429) return response;
const retryAfter = Number(response.headers.get("Retry-After") || 60);
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
}
throw new Error("Exceeded retry attempts");
}
Polling Jobs Without Rate-Limit Errors
Prompt Template
async function waitForJob(jobId, apiKey) { while (true) { const response = await fetch(`https://armox.ai/api/v1/jobs/${jobId}`, { headers: { Authorization: `Bearer ${apiKey}` }, }); if (response.status === 429) { const retryAfter = Number(response.headers.get("Retry-After") || 60); await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000)); continue; } const job = await response.json(); if (["completed", "failed", "cancelled"].includes(job.status)) return job; await new Promise((resolve) => setTimeout(resolve, 10000)); } }
Credits and Billing Behavior
- credits are charged when a run is accepted
- failed jobs are refunded by the execution flow
- monitor usage via
GET /api/v1/account
Common Production Errors
Invalid API key: wrong/expired/revoked keyPublic API access requires ...: subscription not eligibleInsufficient credits ...: top up credits or reduce run costRate limit exceeded: add backoff + queueing
Debugging Checklist
- verify
Authorization: Bearer ...is present - verify endpoint path and method
- log request IDs/job IDs in your app
- capture response headers for rate-limit observability
- persist failed payloads for replay