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"
}
FieldMeaning
typeStable URI that uniquely identifies the error type. An opaque dereferenceable identifier per RFC 7807 — match on code, not on type.
titleShort human-readable summary. May change wording.
statusHTTP status. One status per code.
detailHuman-readable, request-specific. May include input values.
codeStable machine-readable enum. Match on this.
advice_codeMachine-readable next action when applicable.
paramJSON pointer to the failing field for validation errors.
request_idServer-minted ULID, format req_<26-char-ulid>. Quote in support requests.
doc_urlLink 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:

  • code and type never change once shipped. Renamed codes dual-write alongside their replacement for at least six months.
  • title, detail, and advice_code may change wording. Do not match on them.

Error code catalog

Authentication and session

CodeStatusMeaningWhat to do
unauthorized401Missing or malformed Authorization header.Send Authorization: Bearer $ISA_TOKEN.
invalid_token401Token doesn't match any active credential.Check for typos; rotate via the dashboard if leaked.
token_expired401Token past its expiry.Mint a fresh token from the dashboard.

Authorization

CodeStatusMeaningWhat to do
permission_denied403Session is valid but not permitted for this operation.Check the license tier; contact account manager for upgrade.
livemode_mismatch403Test session calling live endpoint, or vice versa.Use the credential that matches the endpoint mode.

Request validation

CodeStatusMeaningWhat to do
validation_error400A request field is missing, malformed, or out of range.Inspect param for the JSON pointer to the failing field.
unknown_field400Request includes a field the schema does not allow.Remove the field; the schemas are strict (additionalProperties: false).
malformed_body400Body is not valid JSON.Validate the JSON before sending.
missing_idempotency_key400Mutating request without Idempotency-Key.Mint a UUID v4 per call.
idempotency_key_format400Idempotency-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_conflict409Idempotency key reused with a different body.Use a new key for the new request.

Resource state

CodeStatusMeaningWhat to do
not_found404The resource does not exist or is not visible to this session.Verify the ID; check livemode.
conflict409The resource is in a state incompatible with the request.Fetch current state; retry against fresh state.
precondition_failed412A required state was not present. See detail.Satisfy the precondition described in detail.

Rate limits and quota

CodeStatusMeaningWhat to do
rate_limit_exceeded429Too many requests in window. Retry-After header tells you when to retry.Honor Retry-After. SDKs do this automatically.
quota_exceeded429Monthly or daily license quota consumed.Contact account manager. Quota does not reset until billing cycle.

Server-side

CodeStatusMeaningWhat to do
internal_error500Unhandled server error. Logged with request_id.Retry with same idempotency key. If persistent, file a ticket quoting request_id.
service_unavailable503A downstream dependency is degraded.Retry with backoff. SDKs do this automatically.
timeout504A 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 (except 429). 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-Key for 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_conflicthttps://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.