Errors
ProblemDetails contract, error code catalog, and how to handle each.
Errors
Match on the typed error subclass. The SDKs throw a typed subclass per
code, so you instanceof instead of string-matching. The wire code is
stable too — match on it only when you don't have the SDK (for example,
piping a raw curl response through jq).
import {
Isa,
IsaApiError,
IsaIdempotencyConflictError,
type PrequalifyRequest,
} from 'isa-sdk';
const isa = await Isa.withBearer();
declare const input: PrequalifyRequest;
try {
await isa.zyins.prequalify(input);
} catch (err) {
if (err instanceof IsaIdempotencyConflictError) { /* mint a new key */ }
else if (err instanceof IsaApiError) {
// Stable err.code, err.requestId, err.status — match on err.code if
// you need to branch by failure mode beyond the typed subclasses.
if (err.code === 'rate_limit_exceeded') { /* honor Retry-After */ }
else if (err.code === 'validation_error') { /* fix err.param */ }
else throw err;
}
else throw err;
}The full catalog is below.
Each SDK ships a typed failure type per code. Names vary by language:
- TypeScript / Python:
Isa<CodeInPascalCase>Error - C# / PHP:
Isa<CodeInPascalCase>Exception - Go:
*zyins.IdempotencyConflictError
See your language's quickstart for the complete SDK error types.
The response shape
{
"type": "https://zyins.isaapi.com/errors/idempotency-conflict",
"title": "Idempotency key reused with different body",
"status": 409,
"detail": "Idempotency-Key '550e8400-...' was used 4 minutes ago with a different request body.",
"code": "idempotency_conflict",
"advice_code": "use_new_idempotency_key",
"param": null,
"request_id": "req_01HZK2N5GQR9T8X4B6FJW3Y1AS"
}| Field | Meaning |
|---|---|
type | Stable URI that uniquely identifies the error type. An opaque dereferenceable identifier per RFC 7807 — match on code, not on type. |
title | Short human-readable summary. May change wording. |
status | HTTP status. One status per code. |
detail | Human-readable, request-specific. May include input values. |
code | Stable machine-readable enum. Match on this. |
advice_code | Machine-readable next action when applicable. |
param | JSON pointer to the failing field for validation errors. |
request_id | Server-minted ULID, format req_<26-char-ulid>. Quote in support requests. |
doc_url | Link to the remediation page for this code. Omitted when the error has no page yet. |
The response carries a doc_url that links to the remediation page — see Error pages.
Field stability:
codeandtypenever change once shipped. Renamed codes dual-write alongside their replacement for at least six months.title,detail, andadvice_codemay change wording. Do not match on them.
Error code catalog
Authentication and session
| Code | Status | Meaning | What to do |
|---|---|---|---|
unauthorized | 401 | Missing or malformed Authorization header. | Send Authorization: Bearer $ISA_TOKEN. |
invalid_token | 401 | Token doesn't match any active credential. | Check for typos; rotate via the dashboard if leaked. |
token_expired | 401 | Token past its expiry. | Mint a fresh token from the dashboard. |
Authorization
| Code | Status | Meaning | What to do |
|---|---|---|---|
permission_denied | 403 | Session is valid but not permitted for this operation. | Check the license tier; contact account manager for upgrade. |
livemode_mismatch | 403 | Test session calling live endpoint, or vice versa. | Use the credential that matches the endpoint mode. |
Request validation
| Code | Status | Meaning | What to do |
|---|---|---|---|
validation_error | 400 | A request field is missing, malformed, or out of range. | Inspect param for the JSON pointer to the failing field. |
unknown_field | 400 | Request includes a field the schema does not allow. | Remove the field; the schemas are strict (additionalProperties: false). |
malformed_body | 400 | Body is not valid JSON. | Validate the JSON before sending. |
missing_idempotency_key | 400 | Mutating request without Idempotency-Key. | Mint a UUID v4 per call. |
idempotency_key_format | 400 | Idempotency-Key on a /v3/* endpoint is not a UUID v4. | Mint the key with a UUID v4 library; never derive it from the body. |
idempotency_conflict | 409 | Idempotency key reused with a different body. | Use a new key for the new request. |
Resource state
| Code | Status | Meaning | What to do |
|---|---|---|---|
not_found | 404 | The resource does not exist or is not visible to this session. | Verify the ID; check livemode. |
conflict | 409 | The resource is in a state incompatible with the request. | Fetch current state; retry against fresh state. |
precondition_failed | 412 | A required state was not present. See detail. | Satisfy the precondition described in detail. |
Rate limits and quota
| Code | Status | Meaning | What to do |
|---|---|---|---|
rate_limit_exceeded | 429 | Too many requests in window. Retry-After header tells you when to retry. | Honor Retry-After. SDKs do this automatically. |
quota_exceeded | 429 | Monthly or daily license quota consumed. | Contact account manager. Quota does not reset until billing cycle. |
Server-side
| Code | Status | Meaning | What to do |
|---|---|---|---|
internal_error | 500 | Unhandled server error. Logged with request_id. | Retry with same idempotency key. If persistent, file a ticket quoting request_id. |
service_unavailable | 503 | A downstream dependency is degraded. | Retry with backoff. SDKs do this automatically. |
timeout | 504 | A downstream call exceeded its deadline. | Retry with same idempotency key. |
Retry policy
The SDKs apply this automatically. If you're calling the API directly, follow this:
- Retry:
429,500,502,503,504 - Do not retry:
4xx(except429). These are deterministic — the request is malformed and will fail the same way every time. - Backoff: exponential, starting at 500 ms, capped at 30 s, with jitter
- Max attempts: 5 total (1 original + 4 retries)
- Idempotency: reuse the same
Idempotency-Keyfor all attempts. A fresh key per attempt defeats deduplication and risks double-execution.
Error pages
Every code in the catalog has a remediation page with examples and known causes.
Use the doc_url in the response — it's the fastest path. If you need to build the link yourself, use the slug errors-<code> with the underscore-form code from the response.
Example: idempotency_conflict → https://docs.isaapi.com/docs/errors-idempotency_conflict
The type URI is an opaque identifier, not a docs link.
Reporting an error
Include the request_id from the error response in any support ticket. It correlates directly to server logs and gets you a fast diagnosis. Without it, support has to triangulate from your account ID and a time window — much slower.
Service status
If you see widespread 503 service_unavailable or 504 timeout responses (not isolated to one request), check support-and-status before filing a ticket.
A public status page is planned for GA. Until then, incident notifications go to the email on your account. Subscribe to get alerts when degradation occurs.
Standards
Errors conform to RFC 7807 Problem Details with Content-Type: application/problem+json.
The code and type fields are the stable contract. Deprecated values dual-write alongside their replacement for at least six months.
Updated about 10 hours ago