selo CLI exits with a code your pipeline can trust.
Prerequisites
- An x402 endpoint you own on Algorand Mainnet. It must answer an unpaid request with an x402 v2
402that offers anexactUSDC payment (ASA31566704), and it must be served over public HTTPS on the default port. Selo testsGETandPOSTroutes priced at up to 0.50 USDC. - A way to publish a file at your origin. You serve one line at
https://<your origin>/.well-known/selo-verification.txtto prove you own the route. - A Mainnet payer wallet. An Algorand account opted in to USDC (ASA
31566704) that holds at least 1.00 USDC per release test, plus enough ALGO for the account’s minimum balance and the opt-in transaction. Use a dedicated wallet that holds only what a few release tests cost. - Node 24 and pnpm 10.
Authorization and preflight are free. You pay only for the release test itself: 1.00 USDC to Selo. Selo pays your endpoint’s price from its own wallet. See Pricing and limits.
Run it
1
Clone and install
The CLI runs from a checkout of the Selo repository.
Terminal
pnpm selo … works from anywhere inside the checkout. Relative file paths resolve from the directory you run it in.Set two variables for the rest of this guide. Replace the URL with your own paid route:Terminal
2
Authorize your endpoint
Ask Selo for a verification challenge for the exact URL and method:The CLI prints the authorization id (On success the CLI prints
Terminal
auth_…, status PENDING), the URL to serve, the line to serve, and the verify command to run next. The line looks like selo-verification= followed by a random token.Serve that line at https://<your origin>/.well-known/selo-verification.txt. The file may hold several lines, must answer with a 2xx status and must be at most 4,096 bytes. Then verify:Terminal
authorization auth_…: VERIFIED, the method and route it covers, and when it expires, and exits 0. An authorization is valid for 24 hours after verification. You have 1 hour to verify a new challenge before it expires.3
Run a free preflight
A preflight makes one unpaid request to your endpoint, reads its
402, and tells you what the test will cost before anyone pays.Terminal
--body is a JSON file with the request body to send. It is allowed only with --method POST; omit it for GET.An eligible preflight prints:If the target is not eligible, the CLI prints
ineligible (<reason>) with a message and exits 3. Nothing is paid. The reasons are listed in Run a preflight.You do not have to keep this preflight id.
selo test runs its own fresh preflight on every run.4
Write your release contract
Declare what a paid response must look like. Write All three fields are optional. The schema is compiled in strict mode before anything is paid: every name in
contract.json with the status, content type and JSON Schema that your paid route actually returns:contract.json
required must also appear under properties, or the CLI exits 3. See Write a release contract.5
Run the paid release test
Export the payer wallet’s 25-word mnemonic in The Mainnet flags are required and deliberate:
SELO_PAYER_MNEMONIC and run the test. The CLI never prints the mnemonic or writes it to disk.Terminal
Before signing, the CLI prints the terms: your release, the target, the preflight, the target fee, Selo’s cap, what you pay and on which network, your approved budget and the payer address. It then prints the price, network, payTo and tag read from Selo’s live
402. It pays once and never retries a payment on its own. Every flag is documented in selo test.6
Read the result
After the report comes back, the terminal shows:
verdict: PASS, FAIL or INCONCLUSIVE.- One
checkline per release check, with its status and code, for exampleresponse_contract FAIL SCHEMA_MISMATCH. - Any
warninglines. job: the job id (job_…).inbound: the transaction where you paid Selo.downstream: the transaction where Selo paid your endpoint.report: the private report link, redacted. The full link is kept only in.selo/runs/<release>.json.gate:ALLOWorBLOCK, the exit code and the reason, for examplegate ALLOW (exit 0): PASS on every release checkorgate BLOCK (exit 1): FAIL: response_contract.
Terminal
Look both transactions up on an Algorand explorer at
https://allo.info/tx/<txId>. The inbound one always comes first.Files the run leaves behind
Here is the summary from a real Mainnet run against the demo merchant:
selo-gate.json from the fixed-v2 run on 26 October 2026
selo-gate.json from the fixed-v2 run on 26 October 2026
selo-gate.json
Verify the signed verdict
Anyone can check the attestation offline against Selo’s published keys.selo verify exits with the attested verdict and refuses an attestation for any other release, URL or method:
Terminal
--keys instead of the URL. See Verify a signed verdict.
Troubleshooting
Interrupted runs are covered in detail in Recover an interrupted run.
Next steps
Gate deploys in GitHub Actions
Run the free preflight on every build and promote only a signed PASS.
How Selo works
The two payment legs, the order they happen in, and how the verdict is decided.
The five release checks
What each check proves and every code it can return.
Try the demo merchant
See a healthy endpoint fail its contract, then pass after the fix.