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 response currently offers eight legs: SOL, USDC, USDT, and WETH on Solana mainnet plus USDC, USDT0, MON, and WETH on Monad mainnet. 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, or WETH 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 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 points to storage, not to the gateway; this is intentional because upload bytes should bypass the gateway request-body cap.

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 → POST confirm_url

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

Call
PUT upload_url → POST confirm_url
Auth
URL-embedded token

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, POST confirm_url; that is what records size_bytes and content_hash in the locker manifest.

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"

curl -sS -X POST "$ANZA_CONFIRM_URL" | 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 so the gateway records size_bytes + content_hash.
curl -sS -X POST "$MOV_CONFIRM_URL" | 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}
Auth
None

Attestation has two phases. 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
curl -sS -X POST "https://api.nukez.xyz/v1/storage/attest?receipt_id=$RECEIPT_ID" \
  | 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":    "90c884e6",
    "file_count":  5,
    "total_bytes": 187168461,
    "files":       [ /* per-file size + content_hash */ ]
  },
  "on_chain_anchor": {
    "type":        "switchboard_v2",
    "tx":          "qL2HsTPfDgFXMDWd2kZZztDjSwmRUs7CoVhDm9uK945UQNqThRczVPtaDQbqt1mLDMY4gtegHyEX7e82da3vKTQ",
    "slot":        416914165,
    "feed_pubkey": "7wevRnKMrSCYEAdWEuaZn6K9MuNJBSUXLdkXZfxJ5VmY"
  },
  "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 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.