# Nukez — LLM index Name: Nukez Base URL: https://api.nukez.xyz Docs: https://docs.nukez.xyz ## Start here - Discovery: https://docs.nukez.xyz/.well-known/nukez.json — endpoints, CAIP-2 chain ids, providers, auth modes. - LLM tool schema: https://docs.nukez.xyz/v1/tools.json. - OpenAPI: https://docs.nukez.xyz/openapi.json. - Signed-envelope auth required before any authenticated call: https://docs.nukez.xyz/docs/AUTH_SIGNED_ENVELOPE.md. ## Core flow - Five stages: `POST /v1/storage/request` returns HTTP 402 with x402 v2 `accepts[]` envelope; pay chosen leg on-chain; `POST /v1/storage/confirm` with `pay_req_id` in body and tx signature in `X-402-TX` header (alias `X402-TX`; body `tx_sig` fallback); `POST /v1/storage/signed_provision` creates locker; then file ops under `/v1/lockers/{locker_id}/files`. - `/v1/storage/request` always answers 402 (challenge, not error). Body: `x402Version: 2`, `resource`, `accepts[]`, `error`, `extensions.nukez` with `terms`, `instructions`, `price_summary` (`unit_price_usd`, `units`, `total_usd`, `provider`). Compact base64 copy in `PAYMENT-REQUIRED` header. Optional `Idempotency-Key` (alias `X-Idempotency-Key`). - Confirm idempotent: `receipt_id` = first 16 hex of `SHA256("storage|{pay_req_id}|{tx_sig}")`; `locker_id = "locker_" + SHA256(receipt_id).hex()[:12]`. Replay returns existing receipt with `idempotent: true`. Receipts never expire; quotes do (`extra.quote_expires_at`). - Confirm body must echo `pay_asset` (and `pay_network` if multi-chain) matching leg paid. Gateway falls back to quote default only when BOTH omitted; mismatch → 400 " on not in quote". Aliases: `payment_asset`, `payment_chain`. ## Multi-chain support - Solana mainnet (`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`): SOL, USDC, USDT, WETH, BETA. For SPL legs `extra.destination_kind == "spl_token_account"` and `payTo` is already treasury's token account — send `transferChecked` directly; do NOT derive an ATA. Mint/amount/decimals in `extra.spl_transfer`. - Monad mainnet (EVM): MON, USDC, USDT (returned as `USDT0`), WETH. Corpus disagrees on CAIP-2 (`eip155:143` vs `eip155:41454`); trust the value in received `accepts[]` and consult discovery. - Native MON uses `asset: 0x00…00`; ERC-20 legs put token contract in `asset` and call `transfer(payTo, amount)`. - Dev aliases (`solana-devnet`, `monad-testnet`) accepted; not production. - Signatures: Ed25519 (Solana; base58); secp256k1 EIP-191 `personal_sign` (EVM; 0x-hex, 132 chars). Inferred from payer; overridable via envelope `sig_alg` (`"personal_sign"` alias for `secp256k1`). - Confirm tx: `X-402-TX` header (base58 Solana 64–128 chars; 0x-hex 66 chars EVM); body `tx_sig` fallback. ## Assets - Stablecoins (USDC, USDT, USDT0) priced USD, 6-decimal atomic units. SOL uses lamports (1e9); MON wei (18); WETH decimals vary — read `extra.decimals`. - All `accepts[].amount` are raw atomic-unit strings; `extra.human_amount` for display, `extra.decimals` divisor. - Live pricing: `GET /v1/price` (query `units`) or read `extensions.nukez.price_summary` and `accepts[].extra` from the 402. Every priced leg has `extra.price_observation` (Pyth on Solana, Chainlink on Monad, or cross-check). Stablecoins at parity carry none. Assets whose feed is unavailable or fails cross-check are omitted from `accepts[]`. Do not hardcode prices. ## Provisioning - `POST /v1/storage/signed_provision` (payer-signed envelope, `ops: ["locker:provision"]`, envelope `receipt_id` must match body) returns `locker_manifest_v2` with `locker_id`, `receipt_id`, `provider`, `path_prefix`, `attestation_jwt`, `file_api` block of relative paths (`signed_url_default_ttl_min: 30`). `POST /v1/storage/provision` accepts same signed headers; without them, works only in explicit local dev mode. - Optional `operator_pubkey` on confirm/provision binds a delegated signing key (e.g. EVM payer authorizing Ed25519 operator). When set at confirm, payer signs `nukez/confirm/v1|||` (single hyphen if no operator) and delivers as `payer_signature` (body; alias `confirm_signature`) or `X-Nukez-Confirm-Sig`. Enforcement staged via `CONFIRM_INTENT_MODE`; 401 detail carries `sign_this`. - Operators: `POST /v1/lockers/{locker_id}/operators`, `DELETE /v1/lockers/{locker_id}/operators/{pubkey}`; up to 5 per locker; owner-only (`locker:admin`). Operator envelopes set `signer` = operator pubkey. ## Storage providers - Selected at `/v1/storage/request` via `provider`; locked at confirm/provision. Discovery lists enabled providers; corpus enumerates `gcs`, `s3`, `storj`, `mongodb`, `arweave`, `filecoin` (discovery also lists `firestore`). - Signed-URL providers (`gcs`, `s3`, `storj`): pre-authenticated PUT/GET via short URLs that 307-redirect; subsequent `POST /v1/files/confirm` required so gateway downloads, hashes, records `content_hash`, `size_bytes`, `hash_recorded_at`. - Proxy providers (`mongodb`): hash inline at write time; no separate confirm. - Content-addressed (`arweave`, `filecoin`): return `provider_ref` (CID or Arweave tx ID); bytes proxied. May transiently 404 `CONTENT_PROPAGATION_PENDING`, `retryable: true`, `suggested_delay: 15`. For unreachable objects, `expected_hash` may be recorded as `content_hash`; `provider_ref` is integrity proof and attestation never re-downloads. - Size caps: MongoDB 16 MiB per doc (enforced pre-write via `expected_size_bytes`); Arweave ~5 MiB. ## File operations (all require signed envelope) - `POST /v1/lockers/{locker_id}/files` (`locker:write`): body `filename` (regex `[a-zA-Z0-9_][a-zA-Z0-9._/\-]{0,254}`; `.memory/` prefix allowed), `content_type`, `ttl_min` (1–1440, default 30), `expected_hash`, `expected_size_bytes`, `upload_mode` (`"put"`|`"resumable"`). Response: `upload_url`, `download_url`, `upload_headers`, `urls_expire_in_sec`, and (when receipt bound) `confirm_url`/`confirm_required: true`. Batch: `POST /v1/lockers/{locker_id}/files/batch` (≤100). - `GET /v1/lockers/{locker_id}/files` (`locker:list`); `GET /v1/lockers/{locker_id}/files/{filename}` (`locker:read`) re-mints URLs; `DELETE …/files/{filename}` (`locker:write`). - `GET /v1/lockers/{locker_id}/manifest` (`locker:read`) returns `locker_files_v1`: `files[]`, `file_count`, `total_bytes`, `hashed_file_count`, `created_at`, `updated_at`. Per-file: `filename`, `content_type`, `object_key`, `provider`, `content_hash`, `size_bytes`, `hash_recorded_at`, `expected_hash`, `expected_size_bytes`, `provider_ref`, `enrichment`, `created_at`, `updated_at`. - `GET /v1/lockers/{locker_id}/record` (`locker:read`) returns: `locker_id`, `receipt_id`, `owner_id`, `provider`, `bucket`, `path_prefix`, `metadata_key`, `operator_ids`, `tags`, `created_at`. - `POST /v1/lockers/{locker_id}/files/urls` (`locker:read`) batch-mints download URLs (≤100): `urls[]`, `found`, `not_found[]`, `urls_expire_in_sec`. - Bytes travel over short URLs at `https://api.nukez.xyz/f/{token}`. Tokens Ed25519-signed by dedicated short-URL key, method-bound (PUT/GET/DELETE/HEAD; GET also authorizes HEAD). Replay under different method → 403. Default TTL 30 min, max 1440 via `ttl_min`. - Append `?proxy=1` to PUT for single-domain egress: gateway hashes inline, records `content_hash`, reports via `X-Nukez-Content-Hash-Recorded`. Plain PUT gets 307 redirect with `X-Nukez-Confirm-Required: true`; caller must still confirm. - `POST /v1/files/confirm` and `POST /v1/files/confirm-batch` (`locker:write`) record hashes post-redirect. `receipt_id` and `filename`/`filenames` are query params; body literally `{}`. Envelope binds method/path/query/canonical-body; envelope `receipt_id` must equal query; TTL > 300 s rejected — sign at confirm time, after upload finishes. Enforcement staged via `CONFIRM_AUTH_MODE`. - Permanent unauthenticated proxy: `GET /v1/r/{receipt_id}/f/{filename}` (`?download=true` for attachment). Carries `X-Nukez-Content-Hash` when recorded. - `POST /v1/files/fetch-and-store` (`locker:write`) fetches HTTPS URL server-side up to ~100 MiB; SSRF-protected (blocks private ranges, non-HTTPS). ## Auth (signed envelope; request-bound; no bearer tokens) - Headers: `X-Nukez-Envelope` (base64url canonical-JSON, no padding) and `X-Nukez-Signature` (base58 Ed25519, or 0x-hex EIP-191 secp256k1). - Envelope fields: `v` (=1), `locker_id`, `receipt_id`, `nonce` (single-use, ≥8 chars), `iat` (legacy `ts` accepted), `exp` (`exp − iat` ≤ 300 s; ±60 s skew), `ops`, `method`, `path`, `query`, `body_sha256`, optional `sig_alg`, optional `signer` (operator). - Canonical JSON: sorted keys, compact separators (`,` and `:`), `ensure_ascii=False`. `body_sha256` = SHA-256 hex of EXACT wire body — canonicalize once, hash that, send verbatim. - Missing headers: routes declaring both as required FastAPI params (e.g. `/v1/storage/signed_provision`, `/v1/storage/attest`, `/v1/attest/push`, `/v1/storage/recompute-verify`, locker file endpoints as declared) → 422 VALIDATION_ERROR before auth. Routes checking explicitly (`require_signed`, `require_locker_authority`, `/v1/storage/refresh`, `/v1/files/fetch-and-store`, and — once enforced — `/v1/files/confirm[-batch]`) → 401 SIGNED_ENVELOPE_REQUIRED on missing. - Retry: successful nonce briefly caches response (~120 s); replay within window returns verbatim (`idempotent: true`). 409 NONCE_REPLAY only when no cached response; 5xx during processing releases nonce. - Op scopes: `locker:provision`, `locker:refresh`, `locker:read`, `locker:write`, `locker:list`, `locker:urls`, `locker:attest`, `locker:admin`. ## Other useful surfaces - `GET /v1/storage/verification-bundle?receipt_id=X` — self-contained proof: `payment_proof`, `content_proof` (per-file `download_url` under `/v1/r/…`), `on_chain_anchor`, `merkle_algorithm`, `verify_yourself`. No auth. - `GET /v1/storage/merkle-proof?receipt_id=X&filename=Y` — single-file inclusion proof (`leaf_hash`, `leaf_index`, `proof[]` of `{hash, position}`, `merkle_root`, `tree_depth`, `file_entry`). No auth. - `GET /v1/storage/verify` (and POST) — cheap structural verify: `receipt`, `attestation`, `anchor`, `verification` (per-fact booleans), `verified`, `verify_url`, `attestation_hint` when none computed. No auth; no recompute. - `GET /v1/storage/evidence-bundle?receipt_id=X` — portable evidence-v2 bundle (signed envelope, statement digest, anchor object, verification facts, signing key list). Pin gateway keys via `GET /v1/keys` (also `/.well-known/nukez-signing-keys.json`) out of band. `anchor.tx` primary; `switchboard_*` historical only. Anchor confirmation requires `verification.anchor_confirmed`. - `GET /v1/storage/recompute-verify?receipt_id=X` — re-downloads and re-hashes in memory (never writes back). Requires payer envelope with `locker:read`; envelope `receipt_id` must equal query. Compares `result_hash`, not `merkle_root`. - `GET /v1/receipts/{id}` — public receipt; `GET /v1/receipts/{id}/verify` — verifies receipt Ed25519 signature. `GET /v1/receipts/{id}/verify-payment` — re-fetches tx on-chain, returns `binding_verified` and `checks` (`tx_success`, `amount_match`, `payer_match`, `slot_match`, `treasury_received`); SOL, SPL, EVM. - `POST /v1/storage/attest` and `POST /v1/attest/push` (`locker:attest`) — compute Merkle root, Ed25519-sign, anchor on Solana via SPL Memo. Envelope `receipt_id` must equal request or 401 RECEIPT_ID_MISMATCH. - Async default (HTTP 202 + `verify_url`); `?sync=true` polls up to ~90 s. Lifecycle: `pending` → `computed` → `pushing` → `complete`. SPL Memo carries `pid`, `sid`, `dg`, `root`, `n`, `seq`, `t`, `k`. - Auto re-attestation: confirm and delete enqueue background attestation, skipping if manifest unchanged; failures never fail file op. - `GET /v1/short-url/verify-key` returns Ed25519 key for short-URL tokens (`verify_key_hex`, `algorithm: ed25519`). NOT the receipt signer — pin `receipt_signer_pubkey` (from `GET /v1/receipts/{id}`) separately. ## Independent verification - Spec: https://docs.nukez.xyz/docs/verify/merkle-v1.md. Machine: https://docs.nukez.xyz/specs/nukez-merkle-v1.json. Evidence-v2: https://docs.nukez.xyz/specs/nukez-evidence-v2.json. - Leaf: `SHA256("{filename}:{size_bytes}:{content_hash_no_prefix}")`. Files sorted lexicographically. Parent: `SHA256((left_hex + right_hex).encode("utf-8"))`. Odd levels duplicate last node. Final = `merkle_root` (Ed25519-signed, written to SPL Memo). Monad anchor format specified but bridge not currently operational. - `att_code` derived from `result_hash` (not `merkle_root`): strip `sha256:`, first 12 hex, parse int, mod 1e9. Display only, not security primitive. - Receipt verification checks `manifest_signature` and `receipt_sig` against `receipt_signer_pubkey`. For trust-free verification, pin `receipt_signer_pubkey` out of band; `/v1/short-url/verify-key` serves a different key. `anchor` proves the gateway's key committed this snapshot to Solana; it does not prove a third party inspected files. ## Nukez Agent (separate service at https://agent.nukez.xyz) - Discovery: `/v1/card` or `/.well-known/nukez-agent.json` (A2A card at `/.well-known/agent.json`). Subscription-gated NL orchestrator. Your private key never leaves you — service builds envelopes; you sign and return signatures. - Quote: `GET /v1/service/request` returns 402 with `accepts[]`, `price_usd`, `terms` (30-day, `bundled_lockers`, renewal type). Pay, then `POST /v1/service/confirm` with `X402-TX` (or body `tx_signature`/`tx_sig`) and `X-Nukez-Identity`; returns `status: active|renewed`, `service_expires_at`, `lockers_provisioned`, `portal_url`. - Request auth: headers `X-Nukez-Identity`, `X-Nukez-Nonce` (32 random hex bytes, single-use), `X-Nukez-Timestamp` (±300 s), `X-Nukez-Signature` over canonical seven-line message `nukez-request:v1\nmethod=…\npath=…\nidentity=…\nnonce=…\ntimestamp=…\nbody_sha256=…` (path includes query; empty-body hash for GET). - `POST /v1/delegate` accepts NL `task`. Without signing bridge, writes return `status: signing_needed` with `signing_request_id` and `envelopes[]` — sign each `envelope_json` exactly (do not re-serialize), resubmit `{signing_request_id, signatures[]}` in same order. Persist bundle = 5 envelopes: `[create_file, create_index, attest, confirm_data, confirm_index]`. Structured intents: `POST /v1/intent` (`persist`/`recall`/`verify`). - Large files: `POST /v1/blob/init` (`size_bytes`, `content_hash`) → `POST /v1/blob/{upload_id}/part/{part_no}` (`application/octet-stream`) → `POST /v1/blob/{upload_id}/finalize` returns `data_token`; reference as `` in `/v1/delegate`. Downloads: one-time `GET /v1/download/{token}`. - Portal uses passkey (WebAuthn) after keypair-challenge registration; multiple developer keypairs (Solana + EVM) can link to one portal identity via `/v1/portal/auth/link-pubkey`. ## Common failure modes - 402 `TX_NOT_FOUND` at confirm: RPC propagation; SDK backs off (2, 4, 8, 16 s up to `max_retries`, default 5). Safe — `receipt_id` deterministic. - 400 " on not in quote": send exact leg paid. Default fallback only when both fields omitted. - 402 permanent (do not retry): `AMOUNT_MISMATCH`, `WRONG_RECIPIENT`, `QUOTE_EXPIRED`, `DUPLICATE_CONFIRM`, `INVALID_PAY_REQ`, `PAYMENT_VERIFICATION_FAILED`, `INSUFFICIENT_AMOUNT`, `INSUFFICIENT_PAYMENT`, `TX_FAILED`, `TX_REVERTED`, `PAYMENT_OUTSIDE_QUOTE_WINDOW`. - 422 `PAYMENT_OPTION_NOT_IN_QUOTE`: echoed pair wasn't offered — send exact leg paid. - 409 `PAYMENT_ALREADY_ALLOCATED`: one tx buys one pay request; fresh quote + tx. - 410 `quote_expired`: fresh quote. Receipts don't expire. - 401 `CONFIRM_INTENT_REQUIRED`/`CONFIRM_INTENT_INVALID`: binding `operator_pubkey` requires `payer_signature`; 401 body's `sign_this` is exact text. - 422 from signed-envelope endpoint usually = headers entirely missing on routes declaring them required; 401 = present-but-invalid (bad signature, expired, body-hash mismatch, receipt mismatch), or missing on runtime-checked routes. - 401 body-hash mismatch: `body_sha256` ≠ SHA-256 of wire bytes. Canonicalize once, reuse. - 403/404/405 from short URL: token expired or method mismatch. Re-mint via `GET /v1/lockers/{locker_id}/files/{filename}` or `POST /v1/lockers/{locker_id}/files/urls`. - 409 `NONCE_REPLAY`: fresh nonce and `iat`. - 409 `HASH_MISMATCH` at `/v1/files/confirm` when `expected_hash` disagrees. 413 `PAYLOAD_TOO_LARGE` (>16 MiB MongoDB, ~5 MiB Arweave). - 404 `CONTENT_PROPAGATION_PENDING` on Arweave/Filecoin: `retryable: true`, `suggested_delay: 15`. - 410 `endpoint_retired` on `POST /v1/attest/simulate` — use `/v1/storage/evidence-bundle` or `/v1/storage/verify`. - Asset missing from `accepts[]`: feed unavailable or cross-check failed; pay another leg or request fresh quote. - 429 with `Retry-After`: token-bucket (5 rps sustained, burst 10 per client IP; MCP agents independent; `/health`, `/metrics`, preflight OPTIONS exempt). - Every error carries `error_code`, `message`, `details`, `request_id` (also in `X-Request-ID`). ## Docs - https://docs.nukez.xyz/docs/AGENT_BRIEFING.md - https://docs.nukez.xyz/docs/AGENT_FLOW.md - https://docs.nukez.xyz/docs/AUTH_SIGNED_ENVELOPE.md (CRITICAL before any authenticated endpoint) - https://docs.nukez.xyz/docs/ERROR_RECOVERY.md - https://docs.nukez.xyz/docs/CHANGELOG.md - https://docs.nukez.xyz/docs/verify/merkle-v1.md - https://docs.nukez.xyz/specs/nukez-merkle-v1.json - https://docs.nukez.xyz/specs/nukez-evidence-v2.json