Users would usually generate API tokens by using the Connect Wallet button in the Profile page. The workflow below is for paid users who want to manage their tokens in batch from a terminal using cardano-cli.
Endpoints
| Endpoint | Auth | Purpose |
|---|---|---|
POST /auth/proof | Ed25519 sig | Trade a signed message for a 5-minute proof JWT |
POST /auth/register | proofToken | Build / finalize an API key (paid tier; Pro or Premium) |
All return { status, success, msg, data }. The free tier is not issued via this flow — use the public Koios API (no key) or subscribe to Pro/Premium for higher limits.
1. Get a proof token
Sign this message with your stake key:
Koios Auth Proof
Address: <your stake1... reward address>
Timestamp: <unix seconds>The worker checks: signature verifies, public key hashes to the reward address's payment credential, timestamp is within ±5 min.
Download the helper scripts from cardano-community/koios-artifacts:
mkdir -p ~/tmp
curl -fsSL https://raw.githubusercontent.com/cardano-community/koios-artifacts/main/files/grest/utils/koios-website-proof.js -o ~/tmp/sign-proof.mjs
curl -fsSL https://raw.githubusercontent.com/cardano-community/koios-artifacts/main/files/grest/utils/utxos-to-csl.mjs -o ~/tmp/utxos-to-csl.mjs
chmod +x ~/tmp/*.mjs
KOIOS_SITE=https://koios.rest
REWARD=$(cardano-cli latest stake-address build --stake-verification-key-file stake.vkey --mainnet)
PROOF=$(node ~/tmp/sign-proof.mjs "$REWARD" stake.skey \
| curl -s -X POST $KOIOS_SITE/auth/proof \
-H 'Content-Type: application/json' --data-binary @- \
| jq -r '.data.proofToken')2. Build, sign, submit, finalize
The worker computes the price and constructs the tx; you provide a UTXO and sign. No local node required — submission goes through koios's public submit endpoint.
# Step 1: server builds the unsigned tx. The script pulls your UTXOs from
# koios's /address_info directly so you don't need a synced local node.
UTXOS=$(node ~/tmp/utxos-to-csl.mjs "$(cat payment.addr)")
BUILD=$(curl -s -X POST $KOIOS_SITE/auth/register \
-H 'Content-Type: application/json' \
-d "$(jq -n --arg pt "$PROOF" --arg p "my-project" --argjson u "$UTXOS" '{
proofToken: $pt, projID: $p, tier: 2, duration: 30,
tx: $u
}')")
SERIALIZED=$(jq -r '.data.serializedTx' <<<"$BUILD")
TXHASH=$(jq -r '.data.txhash' <<<"$BUILD")
# Step 2: inspect the tx body before signing. Confirm the output goes to
# KOIOS_ADDRESS and the amount matches what you expect to pay.
printf '%s' "$SERIALIZED" | xxd -r -p > /tmp/tx.raw
cardano-cli debug transaction view --tx-body-file /tmp/tx.raw
# Step 3: sign.
cardano-cli latest transaction sign \
--tx-body-file /tmp/tx.raw \
--signing-key-file payment.skey \
--out-file /tmp/tx.signed
# Step 4: submit through koios — no local node needed.
curl -s -X POST https://api.koios.rest/api/v1/submit \
-H 'Content-Type: application/cbor' \
--data-binary @/tmp/tx.signed
# Step 5: finalize. The worker verifies the on-chain payment AND that the tx
# has ≥1 confirmation AND that the inline datum matches tier+duration.
# Skip if the tx was submitted less than ~30 seconds ago — it may not be
# confirmed yet.
curl -s -X POST $KOIOS_SITE/auth/register \
-H 'Content-Type: application/json' \
-d "$(jq -n --arg pt "$PROOF" --arg tx "$TXHASH" --arg p "my-project" '{
proofToken: $pt, projID: $p, tier: 2, duration: 30,
txhash: $tx
}')" | jq '.data | {tier, exp, projID, token}'The worker rejects: underpayments, wrong-address payments, unconfirmed txs, datum mismatches, and cross-address txhash reuse. Overpayments are accepted. (utxos-to-csl.mjs filters to pure-ADA UTXOs only — UTXOs with native tokens, datums, or reference scripts are skipped.)
3. Batch renew
#!/usr/bin/env bash
set -euo pipefail
KOIOS_SITE=https://koios.rest
REWARD=$(cardano-cli latest stake-address build --stake-verification-key-file stake.vkey --mainnet)
PROOF=$(node ~/tmp/sign-proof.mjs "$REWARD" stake.skey \
| curl -s -X POST $KOIOS_SITE/auth/proof \
-H 'Content-Type: application/json' --data-binary @- \
| jq -r '.data.proofToken')
UTXOS=$(node ~/tmp/utxos-to-csl.mjs "$(cat payment.addr)")
for PROJ in project-alpha project-beta project-gamma; do
BUILD=$(curl -s -X POST $KOIOS_SITE/auth/register \
-H 'Content-Type: application/json' \
-d "$(jq -n --arg pt "$PROOF" --arg p "$PROJ" --argjson u "$UTXOS" '{
proofToken: $pt, projID: $p, tier: 2, duration: 30, tx: $u
}')")
SERIALIZED=$(jq -r '.data.serializedTx' <<<"$BUILD")
TXHASH=$(jq -r '.data.txhash' <<<"$BUILD")
printf '%s' "$SERIALIZED" | xxd -r -p > /tmp/tx.raw
cardano-cli debug transaction view --tx-body-file /tmp/tx.raw
cardano-cli latest transaction sign \
--tx-body-file /tmp/tx.raw \
--signing-key-file payment.skey \
--out-file /tmp/tx.signed
curl -s -X POST https://api.koios.rest/api/v1/submit \
-H 'Content-Type: application/cbor' \
--data-binary @/tmp/tx.signed
curl -s -X POST $KOIOS_SITE/auth/register \
-H 'Content-Type: application/json' \
-d "$(jq -n --arg pt "$PROOF" --arg tx "$TXHASH" --arg p "$PROJ" '{
proofToken: $pt, projID: $p, tier: 2, duration: 30, txhash: $tx
}')" \
| jq -r '.data | " \(.projID) → expires \(.exp)"'
doneProof tokens expire after 5 minutes. For longer batches, re-run the sign-proof.mjs step inside the loop (every 4 min is a safe cadence).
Errors
| Response | Meaning |
|---|---|
400 bad request | Missing projID, duration, etc. |
401 Proof token invalid, expired, or wrong kind | Re-sign — clocks must be within 5 min. |
200 Free tier is only available via the wallet flow | CLI can't issue free-tier JWTs. Use the public Koios API or subscribe to Pro/Premium. |
200 Transaction not found on chain | Unknown txhash. Check cardano-cli output. |
200 Transaction not yet confirmed on chain | Wait for ≥1 block confirmation (≈20s on mainnet) before finalizing. |
200 Transaction does not contain a payment output to KOIOS_ADDRESS with the expected lovelace amount | Underpayment, wrong address, missing datum, or datum tier/duration mismatch. |
200 Transaction hash already used for another registration | Another address already finalized this txhash. Find your own txhash or pay for a new registration. |