Errors

Every Appstrate API error follows RFC 9457 with Stripe-style extensions.

Errors are returned as application/problem+json per RFC 9457, with a set of extensions inspired by Stripe.

Format

{
  "type": "https://appstrate.dev/errors/validation-failed",
  "title": "Validation failed",
  "status": 400,
  "detail": "Request body contains invalid fields.",
  "instance": "/api/end-users",
  "code": "validation_failed",
  "requestId": "req_01HZABC...",
  "errors": [
    { "field": "externalId", "code": "required" },
    { "field": "email", "code": "invalid_format" }
  ]
}

Fields

FieldAlwaysDescription
typeYesURI identifying the error class
titleYesHuman-readable summary
statusYesHTTP status code (mirrors the response status)
detailNoHuman-readable explanation for this occurrence
instanceNoURI of the request that produced the error
codeYesStable machine-readable code (see below)
requestIdYesCorrelation id; also in the X-Request-Id response header
paramNoSingle path of the offending field (Stripe-style)
errorsNoArray of field-level errors for validation_failed
retryAfterNoSeconds to wait before retrying (on 429)

Stable codes

CodeTypical statusMeaning
invalid_request400Malformed request that does not fit validation
validation_failed400Zod validation failed. Details in errors[]
unauthorized401No credentials or credentials are invalid
forbidden403Credentials lack the required scope or role
not_found404Resource does not exist or is out of the caller's scope
conflict409Resource state conflict (e.g. duplicate, idempotency key mismatch)
gone410Resource was permanently deleted
operation_not_allowed409 / 422Valid input, invalid state for this operation

See Reference / Error Codes for the full catalog.

Field error codes

When code = validation_failed, each entry in errors[] uses one of these stable field codes:

Field codeMeaning
requiredMissing required field
invalid_typeWrong type (e.g. expected string, got number)
invalid_formatWrong format (e.g. not an email, not an ISO date)
out_of_rangeValue outside allowed min/max
unknown_fieldField is not accepted by the schema

Mapped automatically from Zod issue types.

Retry guidance

For 429 Too Many Requests, the retryAfter field (and the Retry-After response header) tells you how long to wait. For 5xx server errors, retry with exponential backoff; start at 1 second, cap at 60.

409 conflict with code = "conflict" from Idempotency-Key mismatch (same key, different body) should not be retried; the original response is the authoritative one.

Request correlation

Every response carries X-Request-Id: req_.... Include it in support tickets or reproduce it in your logs to correlate with Appstrate's logs. All auth decisions, permission denials, and impersonation events are emitted with the same requestId.

Example: authentication failure

HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json
X-Request-Id: req_01HZ...

{
  "type": "https://appstrate.dev/errors/unauthorized",
  "title": "Authentication required",
  "status": 401,
  "detail": "Invalid or revoked API key.",
  "code": "unauthorized",
  "requestId": "req_01HZ..."
}

Example: scope denial

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json

{
  "type": "https://appstrate.dev/errors/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "Scope 'agents:run' is required.",
  "code": "forbidden",
  "requestId": "req_01HZ..."
}

Example: validation failure

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json

{
  "type": "https://appstrate.dev/errors/validation-failed",
  "title": "Validation failed",
  "status": 400,
  "code": "validation_failed",
  "requestId": "req_01HZ...",
  "errors": [
    { "field": "scopes", "code": "invalid_type" },
    { "field": "name", "code": "required" }
  ]
}

On this page