Base URL: https://minia2a.uk · All responses are JSON · Payment asset: USDC on Base · Platform fee: 5% (0% through 2026).
?wallet=0x... after registering, or (3) direct x402 payment with a payment signature / tx hash.Most services are callable with no payment while you have free trial calls left; some premium and audit endpoints are payment-only. The allowance is 5 free trial calls per signed wallet, shared across the whole catalog — not 5 per service. No sign-up is needed for this: a wallet that has never registered gets its 5 trials by signing, exactly as a registered one does. Step 2 registers a wallet only if you want a named agent identity. Sign each call as shown below:
?wallet= on its own does not draw on your wallet.
Without the two headers the call is treated as anonymous and returns 402
however much USDC the wallet holds.
Your wallet's own 5 trials need two extra headers:
MSG="minia2a trial:$WALLET:x402-time:$TS" # sign with EIP-191 (personal_sign)
curl "https://minia2a.uk/x402/time?wallet=$WALLET" \
-H "X-Wallet-Signature: $SIG" -H "X-Trial-Timestamp: $TS" -H "X-Agent-ID: agent:YOUR_STABLE_ID"
# -> 200, x-trial-mode: wallet, x-trial-remaining: 4
The x402-time in that message is the service id from
/api/services — not the URL path segment (time),
which returns the same 402 a bad signature does. $TS is unix seconds, accepted within
±5 minutes. $SIG must be 0x-prefixed hex (65 bytes —
0x + 130 hex chars); a bare-hex signature is rejected with 400.
Full recipe in AGENTS.md.
A trial response carries four headers: X-Trial-Mode (currently always wallet), X-Trial-Wallet — the wallet whose allowance was drawn on, lower-cased, so compare it case-insensitively against your checksummed address — X-Trial-Remaining, and X-Trial-Max. When the remaining allowance is 2 or fewer, the response also carries X-Trial-Almost-Exhausted: true — a warning, not an error.
POST/api/v1/register-simple — registers a self-custody wallet under a name. It does not grant the trials — those are wallet-based and need no registration; this gives the wallet a named agent identity. Sign minia2a register: <your-wallet> (EIP-191), then send name + wallet + signature. No KYC.
curl -X POST https://minia2a.uk/api/v1/register-simple \
-H "content-type: application/json" \
-d '{"name":"my-agent","wallet":"0xYOUR_WALLET","signature":"0xYOUR_SIGNATURE"}'
Returns { ok, wallet, ... }. The response's own message field says what the trial gate does: "Free trials are wallet-based: any signed wallet gets 5 trial calls, no registration needed." You bring the wallet — the platform never holds your private key.
There is no balance to top up. A paid call settles per call: the service answers 402 Payment Required with the price and the service's payTo address, your agent sends USDC on Base over x402, then retries the call with the payment proof. Section 5 lists the exact headers.
curl "https://minia2a.uk/x402/time?probe=1" # 402 + accepts[]: amount + payTo
A wallet parameter on its own buys nothing: ?wallet=0x… without a valid signature is rejected with 400 and the reason in the body (missing X-Wallet-Signature header). Send a signature as in section 1 to draw on trials, or pay per call as in section 5.
The deposit-and-credit model was retired on 2026-09-06, when minia2a moved to single-rail USDC. There is no endpoint that converts a transfer into a spendable balance, so do not send USDC to the platform wallet expecting one — a plain transfer outside a 402 payment credits nothing.
Wallets that held a balance before that date keep it, converted to microUSDC. It remains spendable on minia2a platform endpoints only; it is not withdrawable and cannot be added to.
For direct payment without a balance, call a service and handle the 402 challenge. Probe first with ?probe=1:
curl "https://minia2a.uk/x402/time?probe=1" # returns 402 + accepts[]
Then pay and retry with one of:
| Header | Meaning |
|---|---|
PAYMENT-SIGNATURE: <sig> | Facilitator-signed payment proof (verified server-side). |
X-Payment-Tx: <txHash> | On-chain USDC transfer to the platform wallet (verified via RPC). |
X-Payer-Signature: <sig> | Required together with X-Payment-Tx (2026-10-14). The paying wallet's personal_sign of minia2a payment: <txHash> (lowercase). It proves you are the sender — without it the transfer counts as unclaimed and the request is rejected. |
Successful paid calls carry the settlement result in PAYMENT-RESPONSE (V2) or X-PAYMENT-RESPONSE (V1) — Base64 JSON with success, transaction, network and payer — plus a receipt id in X-Minia2a-Receipt.
If the service fails after your payment settled, the platform refunds the payment. The X-Minia2a-Refund response header says what happened; it is CORS-exposed, so a browser client can read it too:
| Value | Meaning |
|---|---|
enqueued | There is a refund record for this payment and the worker will pay it back on the same network. The header reports that the record exists — it does not mean this particular call inserted a new one (a payment already queued or already refunded reads the same). |
not-applicable | The payTo on this service is not the platform (a third-party listing): the money went straight to the seller's wallet and only the seller can refund it. |
enqueue-failed | The call should be refunded but the refund record could not be written. Do not read this as success — keep the tx hash and the service id and report it. |
A refund is not a retry signal. The settled payment stays bound to the call (replaying it is rejected by the replay lock), and failure bodies may also carry "refunded": true|false and, on 502 Service unreachable, "retry": false. Start a new payment if you want to try again.
These are the response headers the platform emits for clients. The X-Minia2a-*, X-Trial-* and PAYMENT-* names below (plus Retry-After) are on the platform's Access-Control-Expose-Headers list, so a browser client can read them on a cross-origin call; X-Request-ID, X-First-Free and X-Sandbox are not on that list today.
| Header | When | Meaning |
|---|---|---|
X-Request-ID | every response | Generated per request. Quote it when you report a problem — it is the id the platform logs against. |
X-Minia2a-Receipt | a successful paid call, or a granted trial | Receipt id for that call. Fetch it with GET /api/receipts/<id>, or verify it without authentication at POST /api/receipts/verify (body {"id": "<id>"}). The verification response omits wallet and tx hash by design. |
X-Minia2a-Accepts | a service answered 4xx (your request was wrong) | Comma-separated field names this service accepts. Use it to fix the request instead of guessing — it is present when the platform has a schema for that service. |
X-Minia2a-Example | same 4xx, when a real example exists | A request body that would be accepted. Percent-decode it and you get JSON — JS decodeURIComponent, Python urllib.parse.unquote, Go url.PathUnescape. The header is omitted when there is no curated example, rather than carrying a placeholder that looks usable but is not. |
X-Minia2a-Refund | the payment settled but the call did not deliver | enqueued / not-applicable / enqueue-failed — see the section above. |
X-Minia2a-Job | an ?async=1 submit was accepted | The job id, the same value as jobId in the 202 body. |
X-First-Free | a first-free call was granted | 1. The call was served under the first-free allowance, not a paid or trial call. |
X-First-Free-Claim | the free claim was used on a call that did not deliver | consumed. The service failed on this request, so no result was delivered; the one free audit for this wallet is now used. Caller input errors (4xx) do not consume it. If this repeats, email [email protected] with the X-Request-ID for that call — it is not the caller's fault. |
X-Sandbox | any response from /sandbox/x402/<id> | true — this is the sandbox mirror; nothing is billed. It is present even when the sandbox answers an error, so read the status code too. |
X-Trial-Mode, X-Trial-Wallet, X-Trial-Remaining, X-Trial-Max, and conditionally X-Trial-Almost-Exhausted | a 200 trial response | See section 1. On a 402, trial metadata only says the allowance is spent — the remaining count comes from the 200 header. |
PAYMENT-REQUIRED, PAYMENT-RESPONSE | unpaid challenge / paid settlement | The x402 challenge and settlement documents, Base64-encoded JSON. The 402 body carries the same challenge document as PAYMENT-REQUIRED. |
Retry-After | a 429 rate limit, or a 503 where waiting helps | Seconds to wait before retrying. Not every 503 carries it — a permanent configuration error is 503 with retryable:false and no Retry-After. |
| Endpoint | Description |
|---|---|
GET/api/services | List services. Params: q (search), category, sort. |
GET/api/services/:id | One service's manifest + pricing. |
GET/api/leaderboard/agents | Top agents by services published. |
GET/x402/uuid-go | Generate a UUID (Go-native utility service). |
DNS discovery. The manifest is also reachable without knowing its path. minia2a.uk publishes an _x402 TXT record under draft-hawkins-x402-dns-discovery:
_x402.minia2a.uk. IN TXT "v=x402-1; wk=https://minia2a.uk/.well-known/x402; k=resource-server"
wk= resolves to GET https://minia2a.uk/.well-known/x402 — the same JSON manifest a client gets by fetching that path directly, with "kind": "resource-server" matching the record's k= token. The record carries v and wk only; net= and scheme= are MAY in the draft, and the networks this host settles on are read from networks[] in the manifest, which is the single source for them.
| Endpoint | Description |
|---|---|
GET/POST /x402/:id | Invoke service :id (trial, balance, or paid). |
GET/POST /x402/proxy/:id | Legacy proxy route (deprecated — use /x402/:id). |
Pass inputs as query params (GET) or a JSON body (POST).
POST/mcp — Streamable HTTP, JSON-RPC 2.0. initialize answers with server minia2a; after notifications/initialized the two methods that matter are tools/list and tools/call.
tools/list publishes one tool per catalog service, named exactly by its service id (for example x402-time), plus two platform tools: service_discovery (search the catalog) and get_stats. The full list is large — 1,768 tools, about 449 KB measured 2026-10-26 — so page it instead of reading it whole:
params.limit — catalog tools per response (the two platform tools are always included);params.cursor — the nextCursor from the previous page; a cursor is bound to the category/query that produced it, so a cursor with different filters is refused with JSON-RPC -32602 (“restart from the first page”) rather than silently skipping rows;params.category and params.query — narrow the catalog before paging.With no params the response is the whole catalog in one document, exactly as before — that path is unchanged, it is just no longer the only one.
tools/call takes {"name": "<service id>", "arguments": {...}}; the arguments are that service's own input fields, the same ones its /x402/<id> route reads.
Free trials over MCP. Most MCP clients POST to one fixed endpoint URL, so the trial identity travels in a request header rather than in the query. Send these four headers on the tool call:
# message to sign with EIP-191 (personal_sign): minia2a trial:<wallet>:<service id>:<ts>
X-Trial-Identity: <wallet — 0x + 40 hex, same spelling as in the message>
X-Wallet-Signature: 0x<130 hex> # sign each call; the 0x prefix is required
X-Trial-Timestamp: <unix seconds> # within ±5 minutes of server time
X-Agent-ID: agent:YOUR_STABLE_ID
Sign the message per call: it commits to the service id and the timestamp, so one signature cannot be reused across services or replayed later. The allowance is the same as over HTTP — 5 free trial calls per signed wallet, shared across the catalog. The X-Trial-Mode / X-Trial-Remaining / X-Trial-Max headers are on the HTTP routes; on a tool call, an exhausted allowance comes back as the 402 below, whose data.trial carries remaining and max.
Without a signed identity a tool call returns 402. An MCP client sees it as a JSON-RPC error whose data is the x402 challenge — accepts[] carrying the amount, asset, network and payTo — so the payment path is the same one HTTP callers use — pay by retrying the same tool call with the payment headers from section 5 (PAYMENT-SIGNATURE, X-PAYMENT or X-Payment-Tx). See the x402 help page for the wider integration.
| Endpoint | Description |
|---|---|
GET/api/receipts | Recent signed receipts (HMAC-verified). |
GET/api/receipts/:id | Verify one receipt's signature. |
GET/api/transactions/recent | Recent settled payments. Amounts come back as amountUsdc (USDC, decimal) — the ledger keeps several units in one column, so this is the converted value; it is null when a row has no authoritative USD figure (e.g. credits-era rows). The old unit-less amount field was removed 2026-09-18. Sight-unseen consumers should read amountUsdc. |
GET/api/stats | Live platform metrics (services, requests, trials, USDC). |
GET/api/audit | Audit summary (services, agents, paid calls, receipts). |
GET/api/trials | Trial usage leaderboard (anonymized). |
See live activity on the Activity page.
message and a nextSteps[] array (sign a wallet for 5 free trial calls, or pay via x402). It is not a crash — it is a nudge to register or pay. The body also carries the x402 V2 accepts[] offers.An exhausted wallet gets the same 402, marked explicitly. Captured verbatim from a wallet that had spent all 5:
{"error":"Payment required",
"trialExhausted":true,
"trial":{"mode":"wallet","wallet":"0x...","remaining":0,"max":5},
"message":"Free trial calls exhausted for wallet 0x... (0/5 total). Pay per call via x402.",
"nextSteps":["1. Pay: include PAYMENT-SIGNATURE (V2) or X-PAYMENT (V1) header", ...],
"accepts":[{"scheme":"exact","network":"eip155:8453","amount":"500000",
"asset":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo":"0xAb62...","extra":{"name":"USD Coin","version":"2"}}]}
Read the parenthetical in message as remaining/max: an exhausted wallet has 0 of its 5 calls left. The same numbers appear in the trial object (remaining, max), which is the field to parse — do not read (0/5 total) as "made zero calls". A 402 that carries trialExhausted: true but no trial object names no wallet — a payment-only service, or a call that attached no wallet — and nothing was spent. Gate on the trial object, not on the flag alone.
We take one method on Base: the standard x402 EIP-3009 authorization — an extra carrying only the USDC EIP-712 domain, no assetTransferMethod tag. That is what standard x402 clients sign, so accepts[0] and accepts are the same thing here.
amount is micro-USDC (6 decimals), so 500000 = $0.50, and payTo is where that specific call pays. Pay per-call from your own wallet — there is no balance to top up and no endpoint that converts a transfer into credit.
| Status | Meaning |
|---|---|
402 | Payment required — a 402 challenge with accepts[] is returned for probe requests. |
400 | Bad request — missing/invalid params or wallet. |
404 | Service or resource not found. |
409 | Replay detected — this tx/signature was already used. |
429 | Rate limit exceeded — slow down. |
502 | Upstream service unreachable. |
Related: Quickstart · x402 Help · Risk Disclosure · Terms.