Memory · sandbox · browse · critique · judge.
Documents16PDF · Word · Excel · OCR.
Audio20Transcribe · diarize · TTS.
Images27Caption · OCR · resize.
Web39Scrape · screenshot · meta.
Validation25Email · IBAN · IP · VAT.
Conversions20JSON · YAML · UUID.
All endpoints159Full catalog · featured first.
Wallet-only · earn USDC daily.
Sell-side guideEIP-712 · JWT · settlement.
Pricing & take rate3% paywall · 4% proxy.
How settlement worksSettlement runs daily at 00:00 UTC, in USDC. A balance ≥ 1 USDC is paid at the next run (within 24h). A balance below 1 USDC carries over and accumulates across days until it reaches 1 USDC, then it's paid.
Optional Bearer credentials for agents. Issue once with a SIWE (EIP-4361) personal_sign message (action issue_api_key); use t402_live_ prefix on subsequent calls.
Wallet actions use SIWE (EIP-4361): POST /v1/auth/challenge returns a plain-text message and nonceId; sign with personal_sign on Base (chainId 8453); POST the action route with {wallet, signature, message, nonceId}. Key params live in the signed message Resources URNs — never in a side channel. List and revoke also work via GET/DELETE /v1/keys with Bearer scopes or legacy stats signatures.
SIWE action issue_api_key — two-step challenge flow; no Bearer
Flow
POST /v1/auth/challenge Content-Type: application/json { "action": "issue_api_key", "wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878", "params": { "keyName": "agent-prod", "scopes": "read,pay", "validityDays": 30, "dailyCapUsdcMicro": 1000000 } }
{
"nonceId": "0xa1b2c3…",
"message": "tools402.dev wants you to sign…",
"issuedAt": "2026-06-08T08:30:00.000Z"
}POST /v1/auth/key Content-Type: application/json { "wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878", "signature": "0x…", "message": "tools402.dev wants you to sign…", "nonceId": "0x…" }
HTTP/1.1 201 Created Content-Type: application/json { "apiKey": "t402_live_aB3xK9mN2pQ7rS4tU8vW1yZ5cD6fG0hJ", "keyId": 42, "walletAddress": "0xd6e8af2f65b4c9acc7bf14a3096056e89e312878", "name": "agent-prod", "scopes": [ "read", "pay" ], "createdAtMs": 1717842600000, "expiresAtMs": 1720434600000, "dailyCapUsdcMicro": 1000000 }
Plain-text EIP-4361 message returned by POST /v1/auth/challenge — sign with personal_sign (not signTypedData). Params are encoded in Resources URNs.
tools402.dev wants you to sign in with your Ethereum account: 0xd6e8af2f65b4c9acc7bf14a3096056e89e312878 Authorize tools402 to issue a new API key on your behalf. This signature is off-chain and moves no funds. URI: https://tools402.dev Version: 1 Chain ID: 8453 Nonce: a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef1234 Issued At: 2026-06-08T08:30:00.000Z Resources: - urn:tools402:keyName:agent-prod - urn:tools402:scopes:read,pay - urn:tools402:validityDays:30 - urn:tools402:dailyCapUsdcMicro:1000000
curl -X POST "https://api.tools402.dev/v1/auth/challenge" \
-H "Content-Type: application/json" \
-d '{
"action": "issue_api_key",
"wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878",
"params": {
"keyName": "agent-prod",
"scopes": "read,pay",
"validityDays": 30,
"dailyCapUsdcMicro": 1000000
}
}'
# personal_sign the returned message (EIP-4361 plain text), then:
curl -X POST "https://api.tools402.dev/v1/auth/key" \
-H "Content-Type: application/json" \
-d '{
"wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878",
"signature": "0xSIG",
"message": "SIWE_MESSAGE_FROM_CHALLENGE",
"nonceId": "0xNONCE_FROM_CHALLENGE"
}'SIWE action list_api_keys — alternative to GET /v1/keys Bearer
Flow
POST /v1/auth/challenge Content-Type: application/json { "action": "list_api_keys", "wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878", "params": {} }
{
"nonceId": "0xa1b2c3…",
"message": "tools402.dev wants you to sign…",
"issuedAt": "2026-06-08T08:30:00.000Z"
}POST /v1/auth/keys Content-Type: application/json { "wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878", "signature": "0x…", "message": "tools402.dev wants you to sign…", "nonceId": "0x…" }
HTTP/1.1 200 OK Content-Type: application/json { "keys": [ { "id": 42, "prefix": "t402_live_aB3x", "name": "agent-prod", "scopes": [ "read", "pay" ], "revokedAtMs": null } ] }
curl -X POST "https://api.tools402.dev/v1/auth/challenge" \
-H "Content-Type: application/json" \
-d '{
"action": "list_api_keys",
"wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878",
"params": {}
}'
# personal_sign the returned message (EIP-4361 plain text), then:
curl -X POST "https://api.tools402.dev/v1/auth/keys" \
-H "Content-Type: application/json" \
-d '{
"wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878",
"signature": "0xSIG",
"message": "SIWE_MESSAGE_FROM_CHALLENGE",
"nonceId": "0xNONCE_FROM_CHALLENGE"
}'SIWE action revoke_api_key — alternative to DELETE /v1/keys/:id Bearer
Flow
POST /v1/auth/challenge Content-Type: application/json { "action": "revoke_api_key", "wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878", "params": { "keyId": 42 } }
{
"nonceId": "0xa1b2c3…",
"message": "tools402.dev wants you to sign…",
"issuedAt": "2026-06-08T08:30:00.000Z"
}POST /v1/auth/keys/:id/revoke Content-Type: application/json { "wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878", "signature": "0x…", "message": "tools402.dev wants you to sign…", "nonceId": "0x…" }
HTTP/1.1 200 OK Content-Type: application/json { "ok": true, "keyId": 42 }
curl -X POST "https://api.tools402.dev/v1/auth/challenge" \
-H "Content-Type: application/json" \
-d '{
"action": "revoke_api_key",
"wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878",
"params": {
"keyId": 42
}
}'
# personal_sign the returned message (EIP-4361 plain text), then:
curl -X POST "https://api.tools402.dev/v1/auth/keys/42/revoke" \
-H "Content-Type: application/json" \
-d '{
"wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878",
"signature": "0xSIG",
"message": "SIWE_MESSAGE_FROM_CHALLENGE",
"nonceId": "0xNONCE_FROM_CHALLENGE"
}'SIWE action configure_api_key — partial update of name, daily cap, and/or chain preference. At least one field required. No Bearer.
Flow
POST /v1/auth/challenge Content-Type: application/json { "action": "configure_api_key", "wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878", "params": { "keyId": 42, "name": "agent-prod" } }
{
"nonceId": "0xa1b2c3…",
"message": "tools402.dev wants you to sign…",
"issuedAt": "2026-06-08T08:30:00.000Z"
}POST /v1/auth/keys/:id/configure Content-Type: application/json { "wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878", "signature": "0x…", "message": "tools402.dev wants you to sign…", "nonceId": "0x…", "name": "agent-prod" }
HTTP/1.1 200 OK Content-Type: application/json { "ok": true, "keyId": 42, "name": "agent-prod", "dailyCapUsdcMicro": 1000000, "chainPreference": "base" }
Optional body fields: name (string), dailyCapUsdcMicro (integer, 0 = unlimited), chainPreference (base · ethereum · any). Send only fields you change; body must match the signed SIWE resources.
curl -X POST "https://api.tools402.dev/v1/auth/challenge" \
-H "Content-Type: application/json" \
-d '{
"action": "configure_api_key",
"wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878",
"params": {
"keyId": 42,
"name": "agent-prod"
}
}'
# personal_sign the returned message (EIP-4361 plain text), then:
curl -X POST "https://api.tools402.dev/v1/auth/keys/42/configure" \
-H "Content-Type: application/json" \
-d '{
"wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878",
"signature": "0xSIG",
"message": "SIWE_MESSAGE_FROM_CHALLENGE",
"nonceId": "0xNONCE_FROM_CHALLENGE",
"name": "agent-prod"
}'SIWE action query_usage — wallet-signed usage report
Flow
POST /v1/auth/challenge Content-Type: application/json { "action": "query_usage", "wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878", "params": { "fromDay": "2026-06-01", "toDay": "2026-06-08", "keyId": 42 } }
{
"nonceId": "0xa1b2c3…",
"message": "tools402.dev wants you to sign…",
"issuedAt": "2026-06-08T08:30:00.000Z"
}POST /v1/auth/usage Content-Type: application/json { "wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878", "signature": "0x…", "message": "tools402.dev wants you to sign…", "nonceId": "0x…" }
HTTP/1.1 200 OK Content-Type: application/json { "wallet": "0xd6e8af2f65b4c9acc7bf14a3096056e89e312878", "fromDay": "2026-06-01", "toDay": "2026-06-08", "totalUsdcMicro": 250000, "rows": [] }
curl -X POST "https://api.tools402.dev/v1/auth/challenge" \
-H "Content-Type: application/json" \
-d '{
"action": "query_usage",
"wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878",
"params": {
"fromDay": "2026-06-01",
"toDay": "2026-06-08",
"keyId": 42
}
}'
# personal_sign the returned message (EIP-4361 plain text), then:
curl -X POST "https://api.tools402.dev/v1/auth/usage" \
-H "Content-Type: application/json" \
-d '{
"wallet": "0xD6E8aF2F65B4C9ACC7BF14A3096056e89E312878",
"signature": "0xSIG",
"message": "SIWE_MESSAGE_FROM_CHALLENGE",
"nonceId": "0xNONCE_FROM_CHALLENGE"
}'Bearer scope read, or ?wallet=&sig=&ts= stats signature
Request → Response
GET /v1/keys Authorization: Bearer t402_live_… # or wallet signature: GET /v1/keys?wallet=0xD6E8…2878&sig=0x…&ts=1717000000
HTTP/1.1 200 OK Content-Type: application/json { "ok": true }
curl -X GET "https://api.tools402.dev/v1/keys" \ -H "Authorization: Bearer t402_live_…" # or wallet signature: ?wallet=0x…&sig=0x…&ts=1717000000
Bearer with all 5 scopes, or wallet signature headers/query
Request → Response
DELETE /v1/keys/:id
Authorization: Bearer t402_live_…
# or X-Wallet / X-Signature / X-Timestamp headersHTTP/1.1 200 OK Content-Type: application/json { "ok": true }
curl -X DELETE "https://api.tools402.dev/v1/keys/42" \ -H "Authorization: Bearer t402_live_…"
Five scopes from openapi.json ApiKeyScope enum.
| Scope | Description |
|---|---|
| read | List endpoints, stats, and API key prefixes for the wallet. |
| balance:read | Read unified account balance via GET /v1/account. |
| endpoints:write | Publish, update, or soft-delete seller endpoints. |
| pay | Buyer identity scope — x402 X-Payment / X-Session-Token proof still required per paid call. |
| payout:request | Trigger payout toward the registered payout address only (never a caller-supplied destination). |