Get started.

Use SECONDED from any agent that can sign an x402 payment, in three steps. There is no app to install and no account: your agent sends a check to the API, pays for it from its own wallet over x402, and gets the agreed answer with a signed receipt.

What your agent needs.

It needs an x402 client, or any code that can make HTTP requests and sign with a wallet, and a wallet just for checks. Fund it with a few dollars of USDC on Base or Arc, or USDG on Robinhood Chain. Checks pay on Base unless the request names Arc or Robinhood Chain.

These are mainnet funds: every paid check is a real payment from this wallet. Only ordinary wallet (EOA) signatures are accepted; smart-contract wallets are refused before anything is charged. Two doors take payment, and the choice is simple: an agent using a stock x402 SDK pays through the standard x402 door at POST /v1/x402/checks; a custom client that can sign the nonce the 402 supplies may use either door — the original door binds the payment to that nonce. The worked example below uses the standard door. Read the standard door’s contract before paying there: raise the SDK’s $1 default per-payment cap to the quoted price, and write a private recovery record before the first paid send.

A wallet only for checks is safer: if anything goes wrong, only those few dollars are at risk. Why a separate wallet

1Send the check.

For stock x402 SDKs, use the standard door. Here is a Scam Check on one short email. Send the check and its input to /v1/x402/checks, with no payment yet:

curl -i https://api.secondedoracle.xyz/v1/x402/checks \ -H 'Content-Type: application/json' \ -d '{"product":"scam_check","input":{"message":"Urgent: send funds to unlock your account.","source":"email"},"options":{"network":"eip155:8453","max_price":"0.25"}}'

The reply is 402 Payment Required. The payment terms are in the JSON body and, identical, in the base64 PAYMENT-REQUIRED header: accepts[0] names the price, network, asset and payee. This message is Small, so the check costs $0.25. The standard door’s public 402 contains pricing, domain and validity terms plus an opaque nonexclusive ticket, without check/quote/offer IDs, salt, request commitment or exact billable byte count. Each verified payer selects a separate private purchase.

options.network picks where you pay: eip155:8453 for Base, eip155:5042 for Arc, eip155:4663 for Robinhood Chain. options.max_price is the most this check may cost, in US dollars; if the price is higher, the reply is 409 and no payment is asked for. The payee is the same on every network: accepts[0].payTo in the 402 must be 0x010ab46D566cDe25Cca0ee55eb105e781C7Bcf3a; stop if it differs.

2Pay with your x402 client.

Your x402 client signs a payment for exactly those terms and sends the same request again, with the payment in the PAYMENT-SIGNATURE header:

curl -i https://api.secondedoracle.xyz/v1/x402/checks \ -H 'Content-Type: application/json' \ -H "PAYMENT-SIGNATURE: $PAYMENT" \ -d '<the same body as step 1, byte for byte>'

$PAYMENT is the base64 x402 v2 payment created by your SDK. Echo the selected accepts entry unchanged, including accepted.extra. Before the first paid send, save a private recovery record using the recovery hooks. The complete buy.py example handles this and defaults to a $0.25 cap; a larger cap requires an explicit --max-price. A receipt-free 202 is unverified pending information; it proves neither payment nor an answer.

If a request times out, send the same signed payment again. Never sign a new one for the same check: sending the same payment again never charges twice, but a new payment is a new purchase. More in Waiting, timeouts and retries.

3Fetch the answer.

On the standard door, repeat the exact same paid POST with a plain HTTP client, the saved body and the same PAYMENT-SIGNATURE. Never use an automatic payment wrapper for recovery. With recover.py, your private record and trusted public /v1/keys data are all you need:

python recover.py private/purchase-001.json public-keys.json

The helper verifies the receipt’s signed purchase_association against your full original authorization, accepted terms and canonical request, plus billing, before accepting the answer. New records use seconded-door-recovery/v2 and require this association. It classifies status and response shape before reading the receipt, accepts an answer only on HTTP 200, and verifies signed 202 replies as pending with no answer or PAYMENT-RESPONSE. It never signs another payment. Keep the record if it stops while pending; run recovery again later with the same record.

A 202 means the check is still running; wait as Retry-After says. Then your agent gets the signed receipt and, when both models agreed, the answer, and knows what to do with it:

benign
Proceed.
suspicious
Pause and verify through an independent channel.
malicious
Stop and show you.
NOT VERIFIED
No agreed answer. Pause or ask a human. Free: up to 5 free NOT VERIFIED results per wallet in any rolling 24 hours; at the cap, new checks from that wallet wait until one leaves the window. How free results work

Do not read agreement from the HTTP status alone: act only on an agreed answer in a signed receipt, for the exact input you sent — and read the receipt’s coverage list. It names each part of the check as checked, partial, not checked or unavailable for your input; a part marked not checked was not verified, even next to an agreed answer. The fields of the ownership proof and how to verify a receipt are in the docs.

Alternative: original door for custom clients.

A custom client that can sign the server-supplied nonce may instead start with POST /v1/checks. For the same Small Scam Check, the unpaid request is:

curl -i https://api.secondedoracle.xyz/v1/checks \ -H 'Content-Type: application/json' \ -d '{"product":"scam_check","input":{"message":"Urgent: send funds to unlock your account.","source":"email"},"options":{"network":"eip155:8453","max_price":"0.25"}}'

On this original door, the EIP-3009 authorization must use accepts[0].extra.authNonce from the 402 as its nonce. A client-chosen nonce is refused with 400 quote_nonce_required and nothing is charged. Send the same body and signed payment back to /v1/checks.

Fetch GET /v1/checks/$CHECK_ID, taking the ID from seconded.check_id in the 402. Sign the 401 ownership challenge with the paying wallet (it moves no funds), then repeat the GET with the proof in SECONDED-OWNERSHIP. See the original-door steps and proof fields. Stock SDKs should use the standard-door example above.

Waiting, timeouts and retries.

The answer is released once your payment lands on-chain: typically tens of seconds on Arc, usually under 2 minutes on Base, and one to two minutes on Robinhood Chain. A check itself never works longer than about three minutes — a slow answer is fetched, never bought again. Settlement confirmation on a busy chain can occasionally take longer; a pending answer is always recoverable with the same payment. Keep the payment record and resume recovery later. Do not pay again. Quote expiry does not end recovery of an admitted check. Finished-check records are deleted 90 days after last activity; unresolved payments, undelivered paid answers and refunds are kept until resolved. Keep the verified receipt locally: a saved signed receipt stays verifiable offline after server retrieval ends.

202: still running.
Wait as Retry-After says, usually 2–5 seconds, then repeat the same paid POST with a plain HTTP client (or the ownership GET on the original door). To hold the request open instead of polling, send Prefer: wait=25; the API waits up to 25 seconds before replying.
Timeout, or a lost reply after paying.
Send the same signed payment again — it never charges twice and returns the same check — or recover with GET /v1/checks/$CHECK_ID and the ownership proof. Never sign a new payment for a check that may still be running: a new payment is a new purchase. Application replies may carry hints — do_not_resign, poll_after_s, new_quote_allowed — follow them. A plain-text ingress 503 is retryable. Structured 503 errors store_unavailable, internal_error and verification_unavailable are retryable only with do_not_resign: true and new_quote_allowed: false. A retry proves neither payment nor answer entitlement. Other refusals stop recovery and preserve the private record. Honour numeric or HTTP-date Retry-After and poll_after_s, waiting at least one second within the recovery budget. The Python helper allows up to 30 minutes; if it stops pending, resume with the saved record. A verified terminal receipt is different — see the next entry.
A signed receipt saying service_failed: terminal, nothing charged.
The live service returns this as a 503; the helpers recognise it on HTTP 200 or 503. In either case, a reply whose signed receipt says state: service_failed with billing.charged: "no" is final: the check failed on our side, you were not charged, and retrying the same request cannot change it. Verify the receipt, stop polling, and archive your recovery record; when hints.new_quote_allowed is true you may deliberately start a new purchase later, from a fresh 402 and, on the standard door, a new record file. The receipt’s reason names the cause: prefetch_unavailable — a data source the check needed (a chain reader, an official token list, public records) could not be read in time; provider_unavailable — a model provider could not be reached; engine_error — an internal failure on our side. The published recover.py and recover.mjs recognise this receipt, print a clear no-charge result and archive the record.
429: a rate or fair-use limit.
Wait as Retry-After says, then repeat the same request. A 429 never cancels a running check, and its hints say do_not_resign: it is never a reason to sign anything new. The free NOT VERIFIED cap also answers 429; new checks from that wallet wait until the window clears, while running checks continue.
Quote expired before you paid.
A quote lasts about two minutes. If it expires unpaid, nothing was charged: send the unpaid request again for a fresh 402.

The full API contract.

The API describes itself in OpenAPI 3.1, with the exact request and response schema for every route: api.secondedoracle.xyz/v1/openapi.json. GET /v1/products lists each check’s input, prices and payment networks, and POST /v1/quote prices a check for free, before anything is paid.

Agents can read these steps as plain text at secondedoracle.xyz/install.txt, and the agent skill covering both doors at secondedoracle.xyz/skill.md. The standard door’s full contract and recovery examples are at secondedoracle.xyz/docs/x402-door.

Spending limits are yours.

SECONDED installs nothing on your side and keeps no budget for you. What your agent spends is the owner’s responsibility: set options.max_price on every check, set any daily or hourly budget in your agent or x402 client, and keep only a few dollars in the paying wallet.

No check costs more than $2.50. The service applies its own per-wallet rate and fair-use limits, but they protect the service, not your budget.

An MCP plug-in is coming later.

Coming later

An MCP plug-in, with one tool for each check, is coming later. There is no date yet. Until then, the API is how agents use SECONDED, and there is nothing to install.

Test networks.

Testnet

The testnet beta ran on Base Sepolia, Arc testnet and Robinhood Chain testnet, paid with testnet USDC and testnet USDG. It has ended: SECONDED now takes payment on the Base, Arc and Robinhood Chain mainnets only.

A check that names a test network in options.network is refused before anything is paid. Test and mainnet balances are separate: never send mainnet funds to a testnet address.

Stay safe.

Official sources only.
Send checks only to https://api.secondedoracle.xyz, and take the address from secondedoracle.xyz, not from a message, a reply or an ad. Pay only a 402 from that address.
SECONDED never asks for your seed phrase or private key.
Not to pay, not to fetch an answer, and not for a refund. Anyone who asks for one is not SECONDED.
An answer is not advice.
A SECONDED answer is AI-generated: a second check on one exact input. It is not financial or investment advice, not a recommendation to trade, and not a guarantee.
Keep the private recovery record.
On the standard door, keep the exact request, authorization and accepted terms in the private recovery record: the signed purchase_association ties the receipt to that purchase. Public terms tickets cannot reserve, void, consume or read another payer’s purchase. Never share payment headers, SIWX signatures or recovery records. On the original /v1/checks door, keep its salt and original input privately with the receipt; retained records still verify historical IDs and salted commitments.

More good practices for trading agents