- 1Ask for the price.
POST /keyswithout a payment answers402. The body lists oneacceptsentry per pack: the amount in lovelace, the address to pay to, the network. - 2Pay on Cardano. Your client sends that amount to the pay-to address. The transaction spends one of your UTxOs as a nonce, which makes the payment single-use.
- 3Repeat the call with the proof. The signed transaction travels base64-encoded in the
PAYMENT-SIGNATUREheader of the same request. - 4Get the key. The gateway hands the envelope to its facilitator, which submits the transaction and waits for it on chain. The response is
201with the key, the pack's calls and the validity.
Buy a key with tADA
A key or a top-up is paid on Cardano, in one HTTP round trip. No account, no sign-in: the payment is the credential.
Buying with tADA is switched off on this gateway right now. Sign in with a wallet or redeem a code instead.
How it works
http# 1. price
POST https://api.preprod.odatano.dev/keys?pack=500
→ 402 { "x402Version": 2, "accepts": [ {
"scheme": "exact", "network": "cardano:preprod",
"amount": "5000000", "payTo": "addr_test1…",
"extra": { "units": 500 } } ] }
# 3. same call, with the signed payment
POST https://api.preprod.odatano.dev/keys?pack=500
PAYMENT-SIGNATURE: <base64 envelope>
→ 201 { "token": "oda_…", "units": 500, "validUntil": "…" }
Packs
| Calls | Price | Amount | Named pack |
|---|---|---|---|
| … | |||
- Network…
- Validitya bought key is valid for … from the purchase
- Choosing
?pack=<calls>names the pack. Without it the gateway settles against the largest pack the payment covers. - Price per callevery forwarded call costs 1, metadata and the verify lane are free
Top-ups
- With the key
POST /topupwithAuthorization: Bearer oda_…, same 402 round trip - By key id
POST /topup?key=<id>, no secret needed; the id is on the account page - By address
POST /topup?address=<stake address>reaches the key bound to that address. A key bought with tADA is bound to the paying address on the spot. - Replaya spent nonce is refused by the facilitator, a known transaction hash by the gateway (
409)
httpPOST https://api.preprod.odatano.dev/topup?key=<id>&pack=500
PAYMENT-SIGNATURE: <base64 envelope>
→ 200 { "unitsAdded": 500, "unitsLeft": 1000 }
Client
- Packages
@x402/fetch+@x402/cardanoon npm, the official x402 client:wrapFetchWithPaymentdoes the 402 round trip, the Cardano scheme builds and signs the payment from your wallet - Protocolx402 v2, scheme
exacton Cardano, asset lovelace; the 402 carries the requirements in thePAYMENT-REQUIREDheader and in the body - Walleta mnemonic for the reference signer, or any
ClientCardanoSigner(a CIP-30 wallet fits); it needs the pack amount plus the fee on the network above - Sourcegithub.com/x402-foundation/x402, package
typescript/packages/mechanisms/cardano - Also works
@odatano/x402'sx402Fetch(github.com/ODATANO/x402), the library behind the gateway's facilitator
jsimport { wrapFetchWithPayment, x402Client } from '@x402/fetch';
import { toClientCardanoSigner } from '@x402/cardano';
import { ExactCardanoScheme } from '@x402/cardano/exact/client';
// the reference signer: a mnemonic plus a Koios or Blockfrost provider
const signer = toClientCardanoSigner({ mnemonic, network: 'cardano:preprod', provider: { koios: { baseUrl: 'https://preprod.koios.rest/api/v1' } } });
const client = x402Client.fromConfig({ schemes: [{ network: 'cardano:*', client: new ExactCardanoScheme(signer) }], spendControls: false }); // lovelace is not a default asset
const fetchPaid = wrapFetchWithPayment(fetch, client);
const res = await fetchPaid('https://api.preprod.odatano.dev/keys?pack=500', { method: 'POST' });
const { token } = await res.json(); // oda_…