Nukez

Worked examples

Worked examples

HTTP API

Raw gateway access against api.nukez.xyz. Request an x402 quote, pay the selected leg yourself, confirm the transaction, then use signed envelopes for locker and file operations. This is the most explicit path: language-neutral, pasteable, and useful when you want to see the protocol boundaries instead of hiding them behind an SDK.

01#

Request a quote

Ask the gateway for a fresh x402 quote and select one concrete payment leg.

Call
POST /v1/storage/request
Auth
None

The production response currently offers nine legs: SOL, USDC, USDT, WETH, and BETA on Solana mainnet plus USDC, USDT0, MON, and WETH on Monad mainnet. Legs whose treasury configuration is not mounted are silently omitted, so a minimal deployment may show fewer. Always select a leg from the fresh response and carry its network, extra.name, asset, payTo, amount, human_amount, and pay_req_id through payment and confirmation. Quotes expire after 300 seconds, so run quote, pay, and confirm as one short sequence.

Request · bash
RESP=$(curl -sS -X POST "https://api.nukez.xyz/v1/storage/request" \
  -H "Content-Type: application/json" \
  -d '{"units":1,"provider":"gcs"}')
echo "$RESP" | jq .

# Select the payment leg explicitly. Default is native SOL; set PAY_ASSET=USDC,
# USDT, WETH, or BETA for Solana SPL legs, or set PAY_NETWORK=eip155:143 for Monad.
PAY_NETWORK=${PAY_NETWORK:-solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp}
PAY_ASSET=${PAY_ASSET:-SOL}

PAY=$(echo "$RESP" | jq -c --arg n "$PAY_NETWORK" --arg a "$PAY_ASSET" \
  '.accepts[] | select(.network==$n and .extra.name==$a)')
[ -n "$PAY" ] && [ "$PAY" != "null" ] || { echo "payment option not found"; exit 1; }

# Carry every payment variable from the SELECTED leg.
PAY_REQ_ID=$(echo "$PAY" | jq -r '.extra.pay_req_id')
PAY_NETWORK=$(echo "$PAY" | jq -r '.network')
PAY_ASSET=$(echo "$PAY" | jq -r '.extra.name')
PAY_TO=$(echo      "$PAY" | jq -r '.payTo')
PAY_AMOUNT=$(echo  "$PAY" | jq -r '.extra.human_amount')   # CLI display amount
PAY_AMOUNT_RAW=$(echo "$PAY" | jq -r '.amount')            # smallest unit
PAY_ASSET_ID=$(echo "$PAY" | jq -r '.asset')               # native or token mint/contract
PAY_DECIMALS=$(echo "$PAY" | jq -r '.extra.decimals')
QUOTE_EXP=$(echo "$PAY" | jq -r '.extra.quote_expires_at')
Response (one leg per chain shown) · json
{
  "x402Version": 2,
  "accepts": [
    {
      "scheme": "exact",
      "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
      "amount":  "236855000",                                /* lamports */
      "asset":   "So11111111111111111111111111111111111111112",
      "payTo":   "HqrTLaNk89dHPVR5zyMPtEiRnQfabmqc8B9yR3KVbyVp",
      "extra": {
        "name": "SOL",
        "decimals": 9,
        "human_amount": "0.236855",
        "pay_req_id": "7ad9b27a9458",
        "quote_expires_at": 1777642163
      }
    }
    /* + Solana USDC, USDT, WETH, BETA and Monad USDC, USDT0, MON, WETH legs */
  ]
}
02#

Pay on-chain

Send the selected amount to the selected treasury address with your wallet or CLI.

Call
solana / spl-token CLI (or any wallet)
Auth
On-chain signing

For CLI payments, use human_amount for native SOL and Solana SPL transfers. Programmatic agents can use amount in smallest units. For Solana SPL legs, asset is the token mint and payTo is the treasury token account. The fee payer or SPL owner key must be the same key that will own the locker because the receipt owner is derived from the transaction fee payer.

Native SOL leg · bash
solana transfer "$PAY_TO" "$PAY_AMOUNT" \
  --url 'https://mainnet.helius-rpc.com/?api-key=<YOUR_RPC_KEY>' \
  --keypair '/path/to/svm_key.json' \
  --allow-unfunded-recipient

# Copy the printed Signature: <...> into TX_SIG
export TX_SIG=<paste signature>
Solana SPL leg (PAY_ASSET=USDC | USDT | WETH) · bash
spl-token transfer "$PAY_ASSET_ID" "$PAY_AMOUNT" "$PAY_TO" \
  --url 'https://mainnet.helius-rpc.com/?api-key=<YOUR_RPC_KEY>' \
  --owner '/path/to/svm_key.json'

export TX_SIG=<paste signature>
03#

Confirm payment → receipt

Give the gateway the transaction signature and the payment leg you actually used.

Call
POST /v1/storage/confirm
Auth
X402-TX header

Confirmation is a reconciliation step: the gateway checks the on-chain transfer against the stored quote and returns the signed receipt. If tx_not_found appears, retry with backoff; propagation can lag. INVALID_PAYMENT_OPTION means the network or asset does not match the selected accepts[] leg. QUOTE_EXPIRED means restart at the quote step.

Request · bash
CONFIRM=$(curl -sS -X POST "https://api.nukez.xyz/v1/storage/confirm" \
  -H "Content-Type: application/json" \
  -H "X402-TX: $TX_SIG" \
  -d "$(jq -cn --arg pid "$PAY_REQ_ID" --arg net "$PAY_NETWORK" --arg ast "$PAY_ASSET" \
        '{pay_req_id:$pid, pay_network:$net, pay_asset:$ast}')")

echo "$CONFIRM" | jq .
export RECEIPT_ID=$(echo "$CONFIRM" | jq -r '.receipt_id')
Response · json
{
  "ok": true,
  "receipt_id": "a107ea1ad3de433d",
  "receipt": {
    "id": "a107ea1ad3de433d",
    "owner_id":     "BhBeSkwKyqysZstzkqdf4qAcYfS9r27wEMmouvSVfp1U",
    "payer_pubkey": "BhBeSkwKyqysZstzkqdf4qAcYfS9r27wEMmouvSVfp1U",
    "pay_to_address": "HqrTLaNk89dHPVR5zyMPtEiRnQfabmqc8B9yR3KVbyVp",
    "network":   "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
    "pay_asset": "SOL",
    "paid_amount": "0.236687",
    "paid_raw":    236687000,
    "tx_hash":     "F7CpDLBkaFQoGW5NgGAjLYTks25VPJXnXDViDQVnXWQkp2gnTehx6xD51jdu6D5hSR14nXh3XEyKsaSzNGDMxKt",
    "receipt_hash": "b9c3cd9935918e03e1222f5ce362594b18eab7652fda5c21255cc9489bc65303"
  }
}
04#

Provision the locker

Use a signed envelope to create the receipt-bound locker manifest.

Call
POST /v1/storage/signed_provision
Auth
Signed envelope (ops: locker:provision)

The canonical gateway guide uses helper-driven signed calls. Source the helpers once, then send authenticated operations through signed_call METHOD PATH OPS_JSON BODY. The helper builds X-Nukez-Envelope and X-Nukez-Signature from canonical JSON, binding method, path, body hash, receipt, locker, nonce, expiry, and ops to the same Ed25519 signature.

Request · bash
BODY="{\"receipt_id\":\"$RECEIPT_ID\",\"tags\":[]}"
PROV=$(signed_call POST /v1/storage/signed_provision '["locker:provision"]' "$BODY")

echo "$PROV" | jq .
export LOCKER_ID=$(echo "$PROV" | jq -r '.space.locker_id')
Response · json
{
  "ok": true,
  "space": {
    "type":        "locker_manifest_v2",
    "locker_id":   "locker_527830025389",
    "receipt_id":  "a107ea1ad3de433d",
    "provider":    "gcs",
    "bucket":      "nukez",
    "path_prefix": "lockers/locker_527830025389/",
    "encryption":  { "mode": "client_side", "alg": "AES-256-GCM" }
  }
}
05#

Create a file entry → upload URL

Reserve one object path and receive per-file upload, download, and confirm URLs.

Call
POST /v1/lockers/{locker_id}/files
Auth
Signed envelope (ops: locker:write)

Each create_file response is scoped to exactly one object. Keep variables filename-scoped so a later create does not clobber an earlier file's URLs. The upload URL is a gateway short URL: your PUT hits the gateway, which answers with a 307 redirect to the storage provider's signed URL, so the bytes themselves land in storage directly. For anything potentially over 30 MB, resolve that redirect first and PUT the body to the storage URL, because the gateway enforces a 32 MB request-body cap that the redirected upload avoids.

Request · bash
BODY='{"filename":"Anza.pdf","content_type":"application/pdf","ttl_min":30}'
CREATE=$(signed_call POST "/v1/lockers/$LOCKER_ID/files" '["locker:write"]' "$BODY")

ANZA_UPLOAD_URL=$(echo   "$CREATE" | jq -r '.upload_url')
ANZA_DOWNLOAD_URL=$(echo "$CREATE" | jq -r '.download_url')
ANZA_CONFIRM_URL=$(echo  "$CREATE" | jq -r '.confirm_url')
Response · json
{
  "locker_id":    "locker_527830025389",
  "filename":     "Anza.pdf",
  "content_type": "application/pdf",
  "upload_url":   "https://api.nukez.xyz/f/AhNsb2NrZXJfNTI3...",
  "download_url": "https://api.nukez.xyz/f/AhNsb2NrZXJfNTI3...",
  "confirm_url":  "https://api.nukez.xyz/v1/files/confirm?receipt_id=a107ea1ad3de433d&filename=Anza.pdf",
  "urls_expire_in_sec": 1800
}
06#

PUT bytes → signed confirm

Upload bytes directly to storage, then confirm so the manifest records size and hash.

Call
PUT upload_url → POST /v1/files/confirm
Auth
Upload: storage-signed URL · Confirm: signed envelope (ops: locker:write)

The guide calls out a real boundary: anything potentially over 30 MB should use the resolve-redirect pattern, not just obviously huge files. A 33.7 MB KML failed with HTTP 413 until the upload resolved the storage URL first. After the PUT, confirm the file; that is what records size_bytes and content_hash in the locker manifest. Confirm is a signed call under the same locker:write authority as create_file: sign the envelope at confirm time, binding the exact confirm query string and the canonical "{}" body. pynukez 4.0.22 and later already sign confirm. Gateway enforcement is staged behind the CONFIRM_AUTH_MODE setting (currently in shadow mode, which verifies and logs without rejecting); once the mode flips to enforce, an unsigned confirm is rejected with 401 SIGNED_ENVELOPE_REQUIRED, so sign now rather than waiting for the break.

Files under ~30 MB · bash
curl -sS -o /dev/null -w "PUT_HTTP=%{http_code}\n" \
  -L --request PUT \
  -H "Content-Type: application/pdf" \
  --data-binary '@/path/to/Anza.pdf' \
  "$ANZA_UPLOAD_URL"

# Confirm is a signed call: sign a locker:write envelope AT CONFIRM TIME
# (after the upload finishes), binding the confirm query string and the
# canonical "{}" body. Strip the origin so signed_call gets the path.
ANZA_CONFIRM_PATH="${ANZA_CONFIRM_URL#https://api.nukez.xyz}"
signed_call POST "$ANZA_CONFIRM_PATH" '["locker:write"]' '{}' | jq .
Anything potentially over 30 MB · bash
# 1. Preflight: capture the GCS redirect target.
MOV_GCS=$(curl -sS -o /dev/null -w '%{redirect_url}' \
  -X PUT -H "Content-Type: video/quicktime" "$MOV_UPLOAD_URL")

# 2. PUT the body to GCS directly.
curl -sS -o /dev/null -w "PUT_HTTP=%{http_code}\n" \
  -X PUT -H "Content-Type: video/quicktime" \
  --data-binary '@/path/to/locker_test.mov' "$MOV_GCS"

# 3. Confirm with a signed locker:write envelope so the gateway records
#    size_bytes + content_hash.
MOV_CONFIRM_PATH="${MOV_CONFIRM_URL#https://api.nukez.xyz}"
signed_call POST "$MOV_CONFIRM_PATH" '["locker:write"]' '{}' | jq .
Confirm response · json
{
  "locker_id":     "locker_527830025389",
  "filename":      "Anza.pdf",
  "content_hash":  "sha256:9d6500e596f267986b1ab73522a27a5424cd8615b4a65166c486d8933d004237",
  "size_bytes":    5395694,
  "expected_hash": null,
  "hash_verified": false
}
07#

List files in the locker

Inspect the locker manifest after uploads have been confirmed.

Call
GET /v1/lockers/{locker_id}/files
Auth
Signed envelope (ops: locker:list)

This is an authenticated GET, so the envelope still signs the empty-body hash even though there is no request payload. A file can exist before confirmation, but content_hash stays null until confirm_url or confirm-batch records the bytes.

Request · bash
signed_call GET "/v1/lockers/$LOCKER_ID/files" '["locker:list"]' | jq .
Response · json
{
  "locker_id": "locker_527830025389",
  "files": [
    { "filename": "smoke.txt",                "size_bytes": 37,        "content_hash": "sha256:052446cb..." },
    { "filename": "Anza.pdf",                 "size_bytes": 5395694,   "content_hash": "sha256:9d6500e5..." },
    { "filename": "locker_test.mov",          "size_bytes": 147587634, "content_hash": "sha256:e2fd37c0..." },
    { "filename": "NewConstruction.kml",      "size_bytes": 33719838,  "content_hash": "sha256:6afdfdd5..." },
    { "filename": "switchboard_oracles.json", "size_bytes": 465258,    "content_hash": "sha256:b3ee6c87..." }
  ],
  "file_count":  5,
  "path_prefix": "lockers/locker_527830025389/"
}
08#

Attest the locker on-chain

Compute the content Merkle root and anchor the result through Switchboard.

Call
POST /v1/storage/attest?receipt_id={id}&sync=true
Auth
Payer-signed envelope (ops: locker:attest)

Attest is an authenticated endpoint: the call must carry a payer-signed envelope with the locker:attest operation in the X-Nukez-Envelope and X-Nukez-Signature headers, and the envelope binds the exact query string. A bare curl without those headers is rejected with 422 VALIDATION_ERROR before any attestation logic runs, so use the signed_call helper sourced in Step 4 (or the SDK, which signs for you). With sync=true the gateway enqueues the attestation job and polls the persisted result server-side; you usually get the terminal state in one response, or a 202-style accepted response if the roughly 90-second poll ceiling expires first — in that case poll GET /v1/storage/verify. attestation_status="computed" means the gateway-side Merkle math succeeded; "complete" means the Switchboard transaction confirmed on-chain. Timeout and NotEnoughSamples failures are recoverable by retrying attest. Wait for complete before treating Merkle proofs or verification bundles as final.

Request · bash
# This call requires the signed-envelope headers; an unauthenticated
# curl fails with 422 VALIDATION_ERROR. signed_call builds and signs the
# envelope, binding the query string to the locker:attest operation.
signed_call POST "/v1/storage/attest?receipt_id=$RECEIPT_ID&sync=true" '["locker:attest"]' '' \
  | jq '{status: .attestation_status, slot: .switchboard_slot, tx: .switchboard_tx, push_ok: .push_result.ok}'
Response · json
{
  "status":  "complete",
  "slot":    416914165,
  "tx":      "qL2HsTPfDgFXMDWd2kZZztDjSwmRUs7CoVhDm9uK945UQNqThRczVPtaDQbqt1mLDMY4gtegHyEX7e82da3vKTQ",
  "push_ok": true
}
09#

Per-file Merkle inclusion proof

Fetch the live proof for one file and recompute the root locally.

Call
GET /v1/storage/merkle-proof
Auth
None

Use the proof JSON from the current receipt, file, and state. Parse leaf_hash, proof[], position, and merkle_root from the response you just fetched; stale siblings from an older terminal run will verify the wrong tree.

Fetch + verify · bash
PROOF_JSON=/tmp/nukez_merkle_proof_anza.json
curl -sS "https://api.nukez.xyz/v1/storage/merkle-proof?receipt_id=$RECEIPT_ID&filename=Anza.pdf" \
  | tee "$PROOF_JSON" \
  | jq .

python3 - "$PROOF_JSON" <<'PY'
import hashlib, json, sys
H = lambda s: hashlib.sha256(s.encode()).hexdigest()
doc = json.load(open(sys.argv[1]))
cur = doc["leaf_hash"].removeprefix("sha256:")
for step in doc["proof"]:
    sib = step["hash"].removeprefix("sha256:")
    cur = H(cur + sib) if step["position"] == "right" else H(sib + cur)
assert cur == doc["merkle_root"].removeprefix("sha256:"), (cur, doc["merkle_root"])
print(f"verified {doc['filename']} -> {doc['merkle_root']}")
PY
10#

Pull the verification bundle

Download the portable proof package for third-party verification.

Call
GET /v1/storage/verification-bundle
Auth
None

The bundle is meant to travel: payment proof, content proof, Merkle algorithm, on-chain anchor, file list, and verify-yourself instructions in one JSON document. Some payment_proof fields may be intentionally de-duplicated against /v1/receipts/{id}; verify the content root against content_proof.merkle_root and the Switchboard anchor.

Request · bash
curl -sS "https://api.nukez.xyz/v1/storage/verification-bundle?receipt_id=$RECEIPT_ID" \
  | jq .
Response (truncated) · json
{
  "receipt_id": "a107ea1ad3de433d",
  "locker_id":  "locker_527830025389",
  "payment_proof": {
    "tx_signature": "F7CpDLBkaFQoGW5NgGAjLYTks25VPJXnXDViDQVnXWQkp2gnTehx6xD51jdu6D5hSR14nXh3XEyKsaSzNGDMxKt",
    "payer":        "BhBeSkwKyqysZstzkqdf4qAcYfS9r27wEMmouvSVfp1U",
    "explorer_url": "https://explorer.solana.com/tx/F7CpDLBk..."
  },
  "content_proof": {
    "merkle_root": "sha256:22dfae7c2efbb3b4b3306132e18df92b80383cb816255da7d9beb9dafbc4e8ec",
    "att_code":    897578449,
    "file_count":  5,
    "total_bytes": 187168461,
    "files":       [ /* per-file size + content_hash + download_url */ ]
  },
  "on_chain_anchor": {
    "type":         "switchboard_v2",
    "slot":         416914165,
    "tx_signature": "qL2HsTPfDgFXMDWd2kZZztDjSwmRUs7CoVhDm9uK945UQNqThRczVPtaDQbqt1mLDMY4gtegHyEX7e82da3vKTQ",
    "feed_pubkey":  "7wevRnKMrSCYEAdWEuaZn6K9MuNJBSUXLdkXZfxJ5VmY",
    "explorer_urls": {
      "transaction":  "https://explorer.solana.com/tx/qL2HsTPf...",
      "feed_account": "https://explorer.solana.com/address/7wevRnKM..."
    }
  },
  "verify_yourself": {
    "steps": [
      "1. Download each file from its download_url (or /v1/r/{rid}/f/{fn})",
      "2. SHA256 the raw bytes — must match content_hash",
      "3. Build the merkle tree per merkle_algorithm",
      "4. Computed root must match content_proof.merkle_root",
      "5. Look up on_chain_anchor.tx_signature on Solana Explorer; SPL Memo carries the same merkle_root"
    ]
  },
  "verify_page_url": "https://nukez.xyz/verify/a107ea1ad3de433d"
}

Compare the same storage and verification sequence in another surface.