Use this if
Wallet Automation
SIWE signup, wallet-managed keys, and x402 billing for scripts that run from a wallet.
Wallet automation covers SIWE signup, wallet-managed keys, and x402 billing.
Dashboard-managed X-API-Key is still the simplest option. Use SIWE and x402 when the code itself owns signup, key lifecycle, or payment without a browser session.
Where wallet auth fits
Wallet auth solves a specific job: the code owns signup, keys, or billing.
Skip it if
A normal API key already solves the job
Runbook
Go from SIWE challenge to live API key, then add x402 if you need a paid tier.
- 10xArchive
Get a SIWE challenge
POST /auth/web3/challenge with the agent's wallet address. Returns a message to sign. - 2Wallet
Sign the SIWE message locally
The private key never leaves the wallet runtime. Only the signature is sent over the wire. - 30xArchive
Create the account and first key
Submit the signed message to /web3/signup and receive an API key you can use immediately. - 4operator
Call a live route with X-API-Key
Use the returned key on the same REST, CLI, or AI-client paths as any dashboard-managed key. - 50xArchive
Request an x402 quote when needed
POST /web3/subscribe with the target tier. The server returns a 402 payment quote with Base USDC details. - 6Wallet
Sign the USDC authorization
Create the EIP-3009 transferWithAuthorization payload locally, then retry the subscribe call with the payment signature header. - 70xArchive
Switch to the returned key
Every paid subscribe response returns a fresh API key. Downstream clients and scripts should adopt the new key immediately.
Operational jobs
Publicly supported jobs: bootstrap, key lifecycle, and paid-tier changes.
Bootstrap account + key
- Goal
- Create the account and get the first usable API key from a wallet alone.
- Command or route
POST /v1/auth/web3/challenge -> sign message -> POST /v1/web3/signup- Expected output
- A live api_key and tier are returned immediately.
- Next step
- Use the key with REST, CLI, or AI Clients exactly as you would a dashboard-managed key.
List or revoke keys
- Goal
- Inspect active keys or invalidate one without opening the dashboard.
- Command or route
POST /v1/web3/keys POST /v1/web3/keys/revoke- Expected output
- Current key inventory or a revoked key ID you can audit downstream.
- Next step
- Rotate scripts and clients to the surviving key before the revoked one is used again.
Upgrade or renew with x402
- Goal
- Move to Build or Pro, renew the current tier, or queue a lower tier after expiry rules are applied.
- Command or route
POST /v1/web3/subscribe -> receive 402 -> sign EIP-3009 authorization -> retry with payment-signature- Expected output
- A fresh api_key, updated tier, expiry, and tx_hash prove the change.
- Next step
- Adopt the returned key in AI Clients or CLI so the upgraded entitlement is the one actually in use.
Code examples
Get signup and first-key creation working first. Add x402 after that.
TypeScript signup
import { privateKeyToAccount } from 'viem/accounts';import { createWalletClient, http } from 'viem';import { mainnet } from 'viem/chains';
const API = 'https://api.0xarchive.io/v1';const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
// Step 1: Get SIWE challengeconst { message, nonce } = await fetch(`${API}/auth/web3/challenge`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ address: account.address }),}).then(r => r.json());
// Step 2: Sign and submitconst signature = await account.signMessage({ message });const { api_key, tier } = await fetch(`${API}/web3/signup`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message, signature }),}).then(r => r.json());
console.log(`API key: ${api_key} (tier: ${tier})`);Python signup
from eth_account import Accountfrom eth_account.messages import encode_defunctimport requests, os
API = "https://api.0xarchive.io/v1"account = Account.from_key(os.environ["PRIVATE_KEY"])
# Step 1: Get SIWE challengeresp = requests.post(f"{API}/auth/web3/challenge", json={"address": account.address})data = resp.json()
# Step 2: Sign and submitsig = account.sign_message( encode_defunct(text=data["message"]))resp = requests.post(f"{API}/web3/signup", json={"message": data["message"], "signature": sig.signature.hex()})result = resp.json()print(f"API key: {result['api_key']} (tier: {result['tier']})")x402 subscribe
# Step 1: Request pricing (returns 402)resp = requests.post(f"{API}/web3/subscribe", json={"tier": "build"})# resp.status_code == 402payment_info = resp.json()["payment"]# { amount: "49000000", asset: "USDC", network: "eip155:8453",# pay_to: "0x...", asset_address: "0x8335..." }
# Step 2: Sign EIP-3009 transferWithAuthorization# (see x402 spec for full signing flow)# Then retry with payment header:resp = requests.post(f"{API}/web3/subscribe", headers={"payment-signature": base64_payment}, json={"tier": "build"})result = resp.json()# { api_key: "0xa_live_...", tier: "build",# expires_at: "2026-04-06T...", tx_hash: "0x..." }Endpoints
| Method | Path | Description |
|---|---|---|
POST | /v1/auth/web3/challenge | Get a SIWE nonce to sign (10 min TTL) |
POST | /v1/web3/signup | Create account + first API key from a signed SIWE message |
POST | /v1/web3/keys | List active API keys for the wallet |
POST | /v1/web3/keys/revoke | Revoke an API key by ID with a fresh signed request |
POST | /v1/web3/subscribe | Subscribe to Build/Pro via x402 (USDC on Base) and return a fresh API key |
Pricing
SIWE signup is free. Paid tiers are optional and activate through x402.
| Tier | Price | Duration | Payment |
|---|---|---|---|
| Free | $0 | Unlimited | SIWE signup only |
| Build | $49 USDC | 30 days | x402 (USDC on Base) |
| Pro | $199 USDC | 30 days | x402 (USDC on Base) |
Renewals and tier changes
A script can call /web3/subscribe at any time. The server decides whether the purchase renews, upgrades, or queues.
| Scenario | Example | Behavior |
|---|---|---|
| Same-tier renewal | Build (15 days left) → Buy Build again | Extends from current expiry. New expiry = old expiry + 30 days (45 days total remaining). A new API key is returned. |
| Upgrade to higher tier | Build (15 days left) → Buy Pro | Applies immediately. Remaining Build days carry forward: new expiry = old expiry + 30 days. Unused credits from Build are added as bonus credits on Pro. A new API key is returned. |
| Lower-tier purchase (active plan) | Pro (15 days left) → Buy Build | Queued. You keep Pro for remaining 15 days, then automatically transition to Build for 30 days. A new API key is returned. |
| Purchase after expiry | Build (expired) → Buy Build or Pro | Applies immediately. New period starts from now for 30 days. A new API key is returned. |
| Free → Paid | Free → Buy Build | Applies immediately. 30-day subscription starts from now. A new API key is returned. |
Security
Keep the security model boring and explicit: fresh signatures, local private keys, domain validation, and no session tokens.
- No reusable sessions — every request requires a fresh SIWE signature, so the server does not mint a reusable auth token.
- Single-use nonces — challenge nonces are consumed atomically, address-bound, and expire after 10 minutes.
- Domain-locked validation — SIWE messages are validated against the server domain to reduce replay risk.
- Private key stays local — only signatures and payment payloads cross the network.
- Shared auth guardrails — wallet endpoints still sit behind the auth rate limiter, so scripts must handle retries and failures conservatively.