Skip to main content
Selo reports problems with stable, upper-case codes. This page lists every error code the API can return, then the reason codes that appear inside successful responses: preflight rejections, INCONCLUSIVE reasons, spend denials, check statuses and retry outcomes.

Error body

Every failed request returns JSON with two fields:
Error body
string
required
Stable machine-readable code. Branch on this field.
string
required
Human-readable explanation. Its wording can change; do not parse it. For VALIDATION_FAILED it names the field at fault.
Some errors on POST /v1/release-test add fields after a job exists: Two responses do not use this body:
  • 402 on the paid route. The body is {}. The information is in the PAYMENT-REQUIRED header, or in PAYMENT-RESPONSE when settlement failed. See The paid route and x402.
  • An ineligible preflight. POST /v1/preflight returns { "eligible": false, "preflightId", "reason", "message" }. See Preflight rejection reasons.

Error codes

On POST /v1/release-test, every 400, 403, 404, 409 (PREFLIGHT_EXPIRED) and 422 is returned before Selo asks for payment, so you never pay for a request that cannot run.

What to do

Preflight rejection reasons

An ineligible preflight returns eligible: false with one of these reasons. POST /v1/preflight maps each reason to an HTTP status. GET /v1/preflight/{preflightId} returns a stored ineligible preflight with 200. See Run a preflight.

INCONCLUSIVE reasons

A job that ends INCONCLUSIVE carries one inconclusiveReason. PASS and FAIL carry null, because a proven blocking FAIL always wins. When several reasons apply, the first one recorded wins, except PAYMENT_UNRESOLVED, which replaces any other. See Verdicts and the gate.

Spend denial reasons

Before Selo signs a payment to your endpoint, the spend guard evaluates these rules in order and stops at the first that fails. A denial makes the paid_delivery check INCONCLUSIVE with code SPEND_GUARD_DENIED and the summary The spend guard denied the downstream payment: <reason>. See Payments and spend limits.

Check statuses

Each of the five checks reports one status. Every check in the quick profile is blocking. The verdict rule: any blocking FAIL with evidence gives FAIL; otherwise any blocking INCONCLUSIVE, missing check, or PASS without evidence gives INCONCLUSIVE; otherwise PASS. The codes each check can return are listed in The five release checks.

Retry outcomes

The retry_safety check replays the identical signed payment once. Its code is one of these outcomes. See The five release checks.