ODATANOODATANOAPIpreprod
Quickstart · Cardano with ODATANO

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

  • Keyan oda_… key: free with a wallet sign-in (300 calls), or bought with tADA. It goes in Authorization: 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.
  • Toolscurl and jq, and cardano-cli for 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.
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. BuildSimpleAdaTransaction selects the inputs, computes the fee and returns the unsigned transaction with its build id.
  • 2Sign locally. Your key signs the transaction. It never leaves your machine.
  • 3Submit. SubmitTransaction takes the build id and the signed transaction and returns the transaction hash.
  • 4Confirm. CheckSubmissionStatus answers confirmed once 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 unsignedTxCbor through CIP-30 and returns a witness set
  • Submitsend the witness set as signedTxCbor. SubmitTransaction adds it to the built transaction.
  • Review stepCreateSigningRequest, VerifySignature and SubmitVerifiedTransaction check 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, $top and $orderby work 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

MessageWhat it means
401 a gateway key is requiredthe call needs a key in Authorization: Bearer
ODATANO_INSUFFICIENT_FUNDSthe sender holds too little tADA for the amount and the fee. Fund it at the faucet.
recipient output needs at least … lovelaceevery output must carry a minimum of ADA. Raise lovelaceAmount or send ensureMinAda: true.
ODATANO_TX_VALIDATION_FAILEDthe 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_SUBMITTEDthis build was submitted before. Check its status instead of sending it again.
status stays submittednot in a block yet. Check again in a minute.
402 or 429rate limit or used-up calls. Your account shows the calls left.

Next