- Keyan
oda_…key: free with a wallet sign-in (300 calls), or bought with tADA. It goes inAuthorization: Bearer. - Walleta payment key for
cardano-cli, or a browser wallet such as Lace, Eternl or Yoroi switched to preprod - tADAfrom the Cardano testnet faucet. A few tADA cover the transfer and the fee.
- Tools
curlandjq, andcardano-clifor the shell example - Costa handful of calls per transfer: build, submit and a status check every 15 seconds until it is confirmed. The key never pays the fee: that is tADA from your wallet.
First transfer on Cardano
Send tADA through the API. The server picks the inputs and builds the transaction, you sign it with your own key, the server submits it. You need a key and a funded test wallet: no node, no Blockfrost key, no indexer.
Before you start
shell# a payment key and its address
cardano-cli address key-gen \
--verification-key-file payment.vkey \
--signing-key-file payment.skey
cardano-cli address build \
--payment-verification-key-file payment.vkey \
--testnet-magic 1 > payment.addr
# your environment
ODATANO_KEY=oda_…
FROM=$(cat payment.addr) # fund it first
TO=addr_test1…
Four steps
- 1Build.
BuildSimpleAdaTransactionselects the inputs, computes the fee and returns the unsigned transaction with its buildid. - 2Sign locally. Your key signs the transaction. It never leaves your machine.
- 3Submit.
SubmitTransactiontakes the build id and the signed transaction and returns the transaction hash. - 4Confirm.
CheckSubmissionStatusanswersconfirmedonce the transaction is in a block, usually within a minute.
transfer.shAPI=https://api.preprod.odatano.dev
B=$API/odata/v4/cardano-transaction
H=(-H "Authorization: Bearer $ODATANO_KEY"
-H 'Content-Type: application/json')
# 1 build: 2 tADA
jq -n --arg f "$FROM" --arg t "$TO" \
'{senderAddress: $f, recipientAddress: $t,
lovelaceAmount: 2000000}' > req.json
curl -s -X POST "$B/BuildSimpleAdaTransaction" \
"${H[@]}" -d @req.json > build.json
# 2 sign locally
jq '{type: "Tx ConwayEra", description: "",
cborHex: .unsignedTxCbor}' build.json > tx.json
cardano-cli conway transaction sign \
--tx-file tx.json --signing-key-file payment.skey \
--testnet-magic 1 --out-file tx.signed.json
# 3 submit
jq -n --arg b "$(jq -r .id build.json)" \
--arg s "$(jq -r .cborHex tx.signed.json)" \
'{buildId: $b, signedTxCbor: $s}' > submit.json
curl -s -X POST "$B/SubmitTransaction" \
"${H[@]}" -d @submit.json > sub.json
jq '{id, txHash, status}' sub.json
# 4 confirm: repeat until "confirmed"
U="$B/TransactionSubmissions($(jq -r .id sub.json))"
curl -s -X POST "$U/CheckSubmissionStatus" \
"${H[@]}" -d '{}' | jq .status
Signing in a web app
- Serveryour backend calls the API with the key. The key must never reach the browser, and the API takes no calls from browser pages of other sites.
- Browserthe user's wallet signs
unsignedTxCborthrough CIP-30 and returns a witness set - Submitsend the witness set as
signedTxCbor.SubmitTransactionadds it to the built transaction. - Review step
CreateSigningRequest,VerifySignatureandSubmitVerifiedTransactioncheck signer and body before anything is sent
browser// build came from your backend: { id, unsignedTxCbor }
const wallet = await window.cardano.lace.enable();
const witnessSet = await wallet.signTx(build.unsignedTxCbor, true);
// back to your backend, which calls
// SubmitTransaction { buildId: build.id, signedTxCbor: witnessSet }
Read the chain
- Readsblocks, transactions, UTxOs, addresses, pools, epochs and assets as OData under
/odata/v4/cardano. A read is one call. - Query
$select,$filter,$expand,$topand$orderbywork as in any OData service - Explorerthe transaction hash from step 3 opens on preprod.cardanoscan.io
- Other buildsmetadata, native assets, minting and Plutus spends: the same build, sign and submit flow. See the reference.
httpGET https://api.preprod.odatano.dev/odata/v4/cardano/Transactions('<tx hash>')
GET https://api.preprod.odatano.dev/odata/v4/cardano/Addresses('<address>')
Authorization: Bearer oda_…
When something fails
| Message | What it means |
|---|---|
| 401 a gateway key is required | the call needs a key in Authorization: Bearer |
| ODATANO_INSUFFICIENT_FUNDS | the sender holds too little tADA for the amount and the fee. Fund it at the faucet. |
| recipient output needs at least … lovelace | every output must carry a minimum of ADA. Raise lovelaceAmount or send ensureMinAda: true. |
| ODATANO_TX_VALIDATION_FAILED | the node refused the transaction, for example a signature that does not match the sender or an input spent in the meantime. Build again and sign the new one. |
| ODATANO_TX_ALREADY_SUBMITTED | this build was submitted before. Check its status instead of sending it again. |
| status stays submitted | not in a block yet. Check again in a minute. |
| 402 or 429 | rate limit or used-up calls. Your account shows the calls left. |
Next
- MCPfor an AI agent,
@odatano/core-mcpoffers the same reads and builds as tools: AI agents quickstart - Own server@odatano/core runs the same API in your own SAP CAP app
- Docsodatano.dev/docs/odatano: signing methods, Plutus V3 and every build action