Skip to main content
This page describes every object the Selo API returns, field by field. The wire shapes are defined once in Selo’s core package and shared by the API, the CLI and the GitHub Action. Examples come from the two Mainnet runs against the demo merchant on 26 October 2026 (broken-v1 and fixed-v2), or use placeholders such as auth_… for values that are yours.

Conventions

  • IDs are a prefix plus 26 Crockford base32 characters: auth_, pfl_, job_, evd_.
  • USDC amounts are decimal strings with 2 to 6 decimals, such as "1.00" or "0.01".
  • Timestamps are ISO 8601 in UTC.
  • Transaction IDs are Algorand transaction IDs. Look one up at https://allo.info/tx/<txId>.
  • Fields typed … | null are always present and set to null when empty.

Release test response

Returned with 200 by POST /v1/release-test. This is the object the CLI and the GitHub Action gate on.
Release test response (fixed-v2, attestation omitted)
string
required
The release job, job_ plus 26 characters.
string
required
PASS, FAIL or INCONCLUSIVE, decided by deterministic code. Any blocking FAIL with evidence gives FAIL; otherwise any blocking INCONCLUSIVE, missing check, or PASS without evidence gives INCONCLUSIVE; otherwise PASS. See Verdicts and the gate.
string
required
The tested URL.
CheckResult[]
required
All five checks, always in this order: handshake, paid_delivery, response_contract, discovery_contract, retry_safety. See Check result.
string[]
required
One line per WARN check, formatted <check id>: <summary>. Empty when nothing warned.
string | null
required
Why the job is INCONCLUSIVE, or null on PASS and FAIL. One of NETWORK_UNAVAILABLE, FACILITATOR_UNAVAILABLE, TARGET_TIMEOUT, BUDGET_EXHAUSTED, PAYMENT_UNRESOLVED, EVIDENCE_INCOMPLETE, AUTHORIZATION_LAPSED, INTERNAL_ERROR. See INCONCLUSIVE reasons.
object
required
Both payment legs of the job.
string
required
Private report link, https://api.useselo.xyz/v1/reports/<token>. Anyone with the link can read the report, so keep it out of public logs. See Release report.
ReleaseAttestation
Ed25519-signed statement of this verdict. Present when the Selo deployment has a signing key, which the public API has. A repeated request returns the same attestation. See Release attestation.

Check result

One entry of checks in the release test response and in the report.
Check result (broken-v1)
string
required
handshake, paid_delivery, response_contract, discovery_contract or retry_safety. See The five release checks.
string
required
PASS, WARN, FAIL or INCONCLUSIVE. See Check statuses.
string
required
Result code, such as HANDSHAKE_VALID, PAID_AND_DELIVERED, SCHEMA_MISMATCH or NOT_RUN (the check did not run). For retry_safety it is one of the retry outcomes.
boolean
required
Whether the check can decide the verdict. Every check in the quick profile is blocking.
string
required
One sentence describing what Selo observed.
string[]
required
IDs (evd_…) of the evidence records behind the result. Their hashes are listed in the attestation. A PASS with no evidence counts as INCONCLUSIVE.

Release report

Returned with 200 by GET /v1/reports/{token}. It holds everything in the release test response plus the contract, the observed response, every payment and every scenario. It does not carry the attestation.
Release report (fixed-v2, abridged; values in angle brackets are placeholders)
string
required
The release job.
string
required
The project name given when the authorization was created.
object
required
string | null
required
When the checks started.
string | null
required
When the job finished.
string
required
Git commit of the Selo build that ran the job, or unknown.
string | null
required
PASS, FAIL or INCONCLUSIVE. A served report always has a verdict.
string | null
required
As in the release test response.
CheckResult[]
required
The five check results, in fixed order. See Check result.
string[]
required
As in the release test response.
string[]
required
The code of every check that is FAIL or INCONCLUSIVE. For broken-v1 this is ["SCHEMA_MISMATCH", "CATALOG_UNAVAILABLE"].
string | null
required
SHA-256 of the target’s 402 challenge as Selo recorded it. The same value is signed in the attestation.
object | null
required
The release contract you sent, or null when you sent none (Selo then checks only for status 200).
object | null
required
Metadata of the paid response. The body itself is never returned.
object
required
object[]
required
One scenario per check that was planned, in check order.

Release attestation

The attestation field of the release test response: an Ed25519 signature over a statement of the verdict. Verify it offline with the attestation keys. See Signed attestations and Verify a signed verdict.
Release attestation (fixed-v2)
object
required
The signed statement. It holds no secret, no request or response body and no report token.
object
required
Canonical JSON is JSON.stringify of the payload with object keys sorted at every level and no whitespace. Array order is kept. The evidence kind values:

Attestation key set

Returned by GET /.well-known/selo-attestation-keys.json, with Cache-Control: public, max-age=300.
Attestation key set (live)
object[]
required
Every key the deployment signs with. Empty when it has no signing key.
Pin the key you trust instead of fetching the key set at verification time. The CLI’s selo verify checks a signature against pinned keys; see selo verify.

Authorization challenge

Returned with 201 by POST /v1/authorizations.
Authorization challenge
string
required
auth_ plus 26 characters.
string
required
PENDING for a new authorization.
string
required
Origin of the target URL.
string
required
Path of the target URL, without query string. The authorization covers exactly this path.
string
required
GET or POST, the method the authorization covers.
string
required
Where Selo looks for the token: <origin>/.well-known/selo-verification.txt.
string
required
The exact line to put in that file: selo-verification= followed by a 43-character token. Selo keeps only the token’s SHA-256, so this is the only time you see it. The challenge stays open for one hour.

Authorization

Returned by POST /v1/authorizations/{authorizationId}/verify and GET /v1/authorizations/{authorizationId}.
Authorization
string
required
The authorization.
string
required
PENDING: waiting for verification. VERIFIED: Selo may test the target until expiresAt. EXPIRED: the challenge or the authorization lapsed; reading it is what records the change. REVOKED: withdrawn.
string
required
Authorized origin.
string
required
Authorized path.
string
required
GET or POST, the authorized method.
string
required
well_known_file: verified through the well-known file. manual_owner_consent: an explicit owner consent recorded by the Selo operator.
string | null
required
When Selo verified the token, or null while pending.
string
required
While PENDING, when the challenge closes (one hour after creation). Once VERIFIED, when the authorization lapses (24 hours after verification).

Preflight responses

POST /v1/preflight and GET /v1/preflight/{preflightId} return one of two shapes. Branch on eligible.
Returned with 201 by POST /v1/preflight, and with 200 by GET.
Eligible preflight
boolean
required
Always true for this shape. The target can be tested.
string
required
pfl_ plus 26 characters. Pass it to POST /v1/release-test.
object
required
string
required
What Selo expects to pay the target: one paid request at its price.
string
required
What the release test costs you.
string
required
Fifteen minutes after the preflight. GET does not re-evaluate it, so compare this with the current time before paying.