Fel + hastighetsgränser
Ett felkonvolut för varje endpoint. Standard HTTP-statuskoder + en strukturerad code-sträng för programmatisk matchning. Rate-limit-headers på varje svar så att du kan hålla ett jämnt tempo innan du träffar en 429.
Felkonvolut
{
"detail": "Human-readable summary.",
"code": "billing.subscription_past_due",
"field_errors": {
"scheduled_for": ["Must be a future ISO 8601 timestamp."]
}
} detail— alltid närvarande, säker att visa för människor (den är översatt där språket är tillgängligt).code— närvarande för särskiljbara feltillstånd. Stabil mellan API-versioner; matcha på denna för retry-logik.field_errors— närvarande endast vid 400-valideringsfel. Map av fältnamn → lista med meddelanden.
Matris över statuskoder
| Status | Klass | Omförsök? | Vanliga orsaker |
|---|---|---|---|
| 400 | Validering | Nej | Obligatoriskt fält saknas, felaktigt format, brott mot affärsregel |
| 401 | Autentisering | Nej | Saknad / felaktig / återkallad credential |
| 402 | Fakturering | Nej | Prenumeration förfallen, gräns för gratisplan nådd |
| 403 | Behörighet | Nej | Credentialen saknar scope, eller resursen ligger i en annan org |
| 404 | Hittades inte | Nej | Resursen finns inte, eller är inte synlig för din credential |
| 409 | Konflikt | Ibland | Felmatchad återanvändning av Idempotency-Key, brott mot tillståndsmaskin |
| 422 | Obehandlingsbar | Nej | Semantiskt ogiltig kombination av giltiga fält |
| 429 | Hastighetsbegränsad | Ja, med backoff | Per-credential- eller per-org-strypning nådd |
| 500 | Serverfel | Ja, med backoff | Oväntat — öppna ett ärende om det kvarstår |
| 502 / 503 / 504 | Övergående | Ja, med backoff | Uppström / deploy / belastning |
Noterbara felkoder
| Kod | Status | Vad det betyder |
|---|---|---|
billing.subscription_past_due | 402 | Orgens Stripe-prenumeration är förfallen. Hänvisa admin till /admin/billing. |
billing.free_plan_minutes_exhausted | 402 | Free-/Pilot-nivån har använt sina 5 inspektioner. |
billing.signature_pack_exhausted | 402 | Signaturpaketets credits är förbrukade; betala per signatur eller köp ett nytt paket. |
permission_denied | 403 | Credentialen saknar scopet. Se field_errors.required_scope. |
idempotency.key_mismatch | 409 | Samma nyckel, annan body. Använd en ny nyckel. |
session.already_ended | 409 | Anrop av end på en icke-öppen session (vanligtvis ofarligt — end är idempotent, detta är för edge-fallen). |
kyb.not_verified | 403 | QES-signatur begärd på en org som inte har klarat KYB. |
rate_limited | 429 | Per-credential- (60 rpm) eller per-org- (600 rpm) strypning nådd. |
Rate-limit-headers
Varje svar — lyckat eller fel — bär med sig strypningstillståndet:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1716461235 X-RateLimit-Limit— taket som gäller för detta anrop.X-RateLimit-Remaining— hur många anrop som återstår i det aktuella fönstret.X-RateLimit-Reset— Unix-tidsstämpel dåRemainingnollställs.
Vid en 429 sätts även Retry-After (i sekunder) enligt RFC 6585.
Strypnings-scopes
| Scope | Gräns | Fönster |
|---|---|---|
| Per credential | 60 | 1 minut |
| Per org (över alla credentials) | 600 | 1 minut |
Burst-bar under minutens första sekund. Träffa taket och ytterligare anrop inom fönstret ger 429.
Retry-strategi
Exponentiell backoff med jitter för 429 / 5xx; gör inte omförsök på 4xx (utöver 408, 425, 429):
async function withRetry<T>(fn: () => Promise<T>, max = 5): Promise<T> {
let lastErr: unknown;
for (let i = 0; i < max; i++) {
try {
return await fn();
} catch (err: any) {
const status = err?.status;
if (status >= 400 && status < 500 && ![408, 425, 429].includes(status)) {
throw err; // not retryable
}
const base = status === 429 ? (err.retryAfterMs ?? 1000) : 250 * 2 ** i;
const jitter = Math.random() * base * 0.2;
await new Promise((r) => setTimeout(r, base + jitter));
lastErr = err;
}
}
throw lastErr;
} SDK:erna implementerar detta internt vid 429 + 5xx; om du hellre vill hantera omförsök själv, sätt retries: 0 i SDK-alternativen.
Felkorrelation
Varje svar bär med sig en X-Request-Id-header (UUID). Ange den i alla supportärenden — vi kan dra fram hela request-spåret enbart från det id:t.
Vad händer härnäst
- Autentisering — credential-rotation om du ser 401:or
- Paginering + idempotens — mönstren som samspelar med omförsök