Errors
Always {"error":{"message","type","code"}} with a matching HTTP status. Quote the x-request-id response header in bug reports.
JSON
{ "error": { "message": "The model \"nova\" does not exist or you do not have access to it.", "type": "invalid_request_error", "code": "model_not_found" } }| Status | Code | Type | Meaning |
|---|---|---|---|
| 400 | invalid_json, invalid_messages, invalid_parameter, invalid_tools, unsupported_content, system_too_long, context_length_exceeded | invalid_request_error | The request is malformed or too big. |
| 401 | missing_credentials, invalid_credentials, invalid_api_key, api_key_revoked, api_key_expired, invalid_token | authentication_error | No credential, or a bad one. |
| 403 | insufficient_scope, origin_not_allowed, no_plan, no_models, blocked_by_permissions | permission_error | Not allowed. |
| 404 | model_not_found, not_found | invalid_request_error | Unknown model (also when it exists but you may not use it) or endpoint. |
| 405 | method_not_allowed | invalid_request_error | Wrong HTTP method. |
| 413 | request_too_large | invalid_request_error | Body over 256 KB. |
| 429 | rate_limit_exceeded | rate_limit_error | Too many requests a minute. Retry-After says when. |
| 429 | daily_cap_exceeded, monthly_cap_exceeded | insufficient_quota | A service key's token cap is used up. Retry-After runs to the next UTC day or month. |
| 429 | limit_day, limit_week | insufficient_quota | The person's plan allowance is used up. Retry-After runs to the reset. |
| 502 | upstream_error, empty_response | server_error | The model failed. Details are never shown. |
| 503 | api_disabled | server_error | The API is switched off for now. Retry-After: 300. |
| 503 | model_starting, model_unavailable | server_error | The model is waking up or briefly unavailable. Retry after Retry-After. |
What to retry
Retry 429 (after Retry-After) and 503. Do not retry other 4xx errors: fix the request. The example waits for retryAfter seconds and gives up after three attempts:
JavaScript
import { createClient, ArtemiiError } from './artemii.js';
const ai = createClient({ baseUrl: 'https://mayfair-ai.crelloo.workers.dev', apiKey: process.env.ARTEMII_KEY });
async function ask(messages) {
for (let attempt = 0; attempt < 3; attempt++) {
try {
return await ai.chat({ model: 'arlo', messages });
} catch (err) {
if (!(err instanceof ArtemiiError)) throw err;
const retryable = err.status === 429 || err.status === 503; // see Errors and limits
if (!retryable || attempt === 2) {
console.error(err.status, err.code, err.message, 'request id:', err.requestId);
throw err;
}
await new Promise((resolve) => setTimeout(resolve, (err.retryAfter ?? 2) * 1000));
}
}
}
const reply = await ask([{ role: 'user', content: 'Hello' }]);
console.log(reply.choices[0].message.content);Limits
| Limit | Value |
|---|---|
| Requests a minute | A token bucket per key (burst equal to its limit) or per person (30 a minute by default). See the x-ratelimit-* headers. |
| Token caps (service keys) | A daily and a monthly cap (UTC), always set. Checked before the call (refused when the estimated prompt alone would exceed what is left, and the answer is clamped to the room that remains) and counted after it. Calls already in flight can overshoot by their own size. |
| Plan allowance (people) | The same daily and weekly windows as the Artemii app, checked before the call and counted after it. |
| Request body | 256 KB |
| Messages | 200 per request |
Your system text | 16,000 characters |
| Whole conversation | 200,000 characters |
| Output | max_tokens defaults to 4096 and is clamped to 8000 |
| Waiting for a sleeping model | Streamed: up to 8 minutes. Not streamed: a limit set by the gateway, then 503 model_starting. |
Kill switch and revoking
Mayfair can switch the API off; every /v1 call then answers 503 api_disabled while the Artemii app keeps working. Revoking a key takes effect on its next request. Expired keys stop at their expiry.