Integration behavior

Handle errors by code, not message

Every API error uses one envelope and every response includes an X-Request-ID.

{
  "error": {
    "code": "validation_failed",
    "message": "The request could not be accepted.",
    "request_id": "req_...",
    "details": {}
  }
}

message is safe for people and can improve over time. Branch on the stable HTTP status and error.code. Log the request ID with your operation record.

Retry matrix

Status Meaning Default behavior
400 Malformed request or required header Fix the client; do not retry unchanged
401 Missing, invalid, expired, or revoked credential Replace/fix authentication
403 Authenticated but not authorized Fix scopes or role; do not retry unchanged
404 Missing or deliberately tenant-hidden resource Verify tenant and identifier
409 State, concurrency, baseline, or idempotency conflict Read the code; replay only when documented
411 Binary upload omitted Content-Length Send exact byte length
413 Body or source exceeds a limit Reduce the asset; do not retry unchanged
415 Declared media type is not accepted or mismatches Fix media type/source
422 Structurally valid request failed domain validation Correct fields or profile/source compatibility
429 Rate, quota, credit, or concurrency capacity Honor Retry-After; avoid hot loops
503 Required service is temporarily unavailable Back off with jitter and a bounded deadline

Idempotency keys

Create operations require Idempotency-Key. The key is scoped to the authenticated principal, method, and route and retained for at least 24 hours.

  • Same key and same body returns the original result.
  • Same key with a different body returns a conflict.
  • A concurrent request with the same key can return a conflict until the first commits.

Generate a high-entropy key per logical operation. Persist it beside the client operation until the outcome is known.

Idempotency-Key: 0e8052b8-37e6-4e95-9eab-9ab52d390970

Do not generate a fresh key merely because your HTTP client timed out. A fresh key can create duplicate uploads, scans, webhook endpoints, or other resources.

Request IDs

Capture X-Request-ID from success and failure responses. The JSON error repeats it as error.request_id, but the response header is the universal location.

Do not send source content, API keys, or full sensitive URLs in a support message. The request ID and UTC timestamp are the right starting point.

Search documentation