# wallet.prim.sh Agent wallets. Generate keys, hold USDC on Base, and pay any x402 invoice. Base URL: https://wallet.prim.sh Auth: x402 (USDC on Base Sepolia). GET /, GET /pricing, GET /v1/metrics are free. Chain: Base Sepolia (eip155:84532) during beta. Install: curl -fsSL https://wallet.prim.sh/install.sh | sh Limits: Max wallets per owner: 100 --- ## Quick Start 1. POST /v1/wallets with EIP-191 signature → register wallet (free) 2. POST faucet.prim.sh/v1/faucet/usdc → get 10 test USDC 3. Call any paid endpoint → receive 402 → sign payment → resend ## Tips - Wallet registration is free — no x402 payment required. - The signed message must be: Register
with prim.sh at", "message": ""}}
Error codes:
not_found
forbidden
insufficient_balance
wallet_paused
policy_violation
duplicate_request
invalid_request
not_implemented
---
## Endpoints
### GET /
Health check.
Free.
Response (200):
service string "wallet.sh"
status string "ok"
---
### GET /pricing
Machine-readable pricing for all endpoints.
Free.
Response (200):
service string "wallet.prim.sh"
currency string "USDC"
network string "eip155:8453"
routes array Route pricing list
.method string HTTP method
.path string URL path
.price_usdc string Price in USDC (decimal string)
.description string Human-readable description
---
### GET /v1/metrics
Operational metrics. Uptime, request counts, latency percentiles, error rates.
Free.
Response (200):
service string "wallet.prim.sh"
uptime_s number Seconds since last restart
requests object Request counts and latencies by endpoint
payments object Payment counts by endpoint
errors object Error counts by status code
---
### POST /v1/wallets
Register a wallet via EIP-191 signature
Free. No x402 required. Sign message: Register with prim.sh at
Request:
address string required Ethereum address to register (0x... 42 chars, checksummed).
signature string required EIP-191 signature over "Register with prim.sh at ".
timestamp string required ISO 8601 UTC timestamp used in the signed message. Must be within 5 minutes of server time.
chain string optional Chain identifier. Default "base".
label string optional Human-readable label for this wallet.
Response (201):
address string Registered Ethereum address.
chain string Chain identifier.
label string | null Label if provided, null otherwise.
registered_at string ISO 8601 timestamp when the wallet was registered.
created_at string ISO 8601 timestamp when the record was created.
Errors:
400 invalid_request Missing fields or invalid signature format
403 forbidden Signature does not match address
409 duplicate_request Wallet already registered
---
### GET /v1/wallets
List registered wallets owned by the calling wallet
Price: $0.001
Query params:
limit integer optional 1-100, default 20
after string optional Cursor from previous response
Response (200): WalletListResponse
Errors:
402 payment_required x402 payment needed
403 forbidden No wallet address in payment
429 rate_limited Too many requests
---
### GET /v1/wallets/:address
Get full wallet details including balance, policy, and status
Price: $0.001
Path params:
address string required address parameter
Response (200):
address string Ethereum address.
chain string Chain identifier.
balance string USDC balance as a decimal string.
funded boolean Whether the wallet has ever been funded.
paused boolean Whether the wallet is currently paused.
created_by string Address that registered this wallet (or self).
policy SpendingPolicy | null Spending policy, null if none configured.
created_at string ISO 8601 timestamp when the wallet was created.
Errors:
402 payment_required x402 payment needed
403 forbidden Caller does not own this wallet
404 not_found Wallet not found
---
### DELETE /v1/wallets/:address
Permanently deactivate a wallet. Irreversible. Pending fund requests cancelled.
Price: $0.01
Path params:
address string required address parameter
Response (200):
address string Deactivated Ethereum address.
deactivated boolean Always true on success.
deactivated_at string ISO 8601 timestamp of deactivation.
Errors:
402 payment_required x402 payment needed
403 forbidden Caller does not own this wallet
404 not_found Wallet not found
---
### POST /v1/wallets/:address/fund-request
Request USDC funding for a wallet. A human operator can approve or deny.
Price: $0.001
Path params:
address string required address parameter
Request:
amount string required Requested USDC amount as a decimal string (e.g. "10.00").
reason string required Human-readable reason for the funding request.
Response (200):
id string Fund request ID (e.g. "fr_abc123").
wallet_address string Wallet address the request is for.
amount string Requested USDC amount as a decimal string.
reason string Reason provided by the requester.
status FundRequestStatus Current status of the fund request.
created_at string ISO 8601 timestamp when the request was created.
Errors:
400 invalid_request Missing amount or reason
402 payment_required x402 payment needed
403 forbidden Caller does not own this wallet
404 not_found Wallet not found
---
### GET /v1/wallets/:address/fund-requests
List all fund requests for a wallet
Price: $0.001
Path params:
address string required address parameter
Query params:
limit integer optional 1-100, default 20
after string optional Cursor from previous response
Response (200): FundRequestListResponse
Errors:
402 payment_required x402 payment needed
403 forbidden Caller does not own this wallet
404 not_found Wallet not found
---
### POST /v1/fund-requests/:id/approve
Approve a pending fund request. Returns the address to send USDC to.
Price: $0.01
Path params:
id string required id parameter
Response (200):
id string Fund request ID.
status "approved" Always "approved" on success.
funding_address string Send USDC to this address to fulfill the request.
amount string Approved USDC amount as a decimal string.
chain string Chain identifier for the funding transaction.
approved_at string ISO 8601 timestamp when the request was approved.
Errors:
402 payment_required x402 payment needed
403 forbidden Caller not authorized to approve
404 not_found Fund request not found
409 duplicate_request Already approved or denied
---
### POST /v1/fund-requests/:id/deny
Deny a pending fund request
Price: $0.001
Path params:
id string required id parameter
Request:
reason string optional Reason for denial.
Response (200):
id string Fund request ID.
status "denied" Always "denied" on success.
reason string | null Denial reason if provided, null otherwise.
denied_at string ISO 8601 timestamp when the request was denied.
Errors:
402 payment_required x402 payment needed
403 forbidden Caller not authorized to deny
404 not_found Fund request not found
409 duplicate_request Already approved or denied
---
### GET /v1/wallets/:address/policy
Get the spending policy for a wallet
Price: $0.001
Path params:
address string required address parameter
Response (200):
wallet_address string Wallet address this policy applies to.
max_per_tx string | null Max USDC per transaction, null = no limit.
max_per_day string | null Max USDC per day, null = no limit.
allowed_primitives string[] | null Allowed primitive hostnames (e.g. ["store.prim.sh"]), null = all allowed.
daily_spent string USDC spent today as a decimal string.
daily_reset_at string ISO 8601 timestamp when the daily counter resets.
Errors:
402 payment_required x402 payment needed
403 forbidden Caller does not own this wallet
404 not_found Wallet not found
---
### PUT /v1/wallets/:address/policy
Update spending policy for a wallet. All fields optional. Pass null to remove a limit.
Price: $0.005
Path params:
address string required address parameter
Request:
maxPerTx string | null optional Max USDC per transaction. Pass null to remove the limit.
maxPerDay string | null optional Max USDC per day. Pass null to remove the limit.
allowedPrimitives string[] | null optional Allowed primitive hostnames. Pass null to allow all.
Response (200):
wallet_address string Wallet address this policy applies to.
max_per_tx string | null Max USDC per transaction, null = no limit.
max_per_day string | null Max USDC per day, null = no limit.
allowed_primitives string[] | null Allowed primitive hostnames (e.g. ["store.prim.sh"]), null = all allowed.
daily_spent string USDC spent today as a decimal string.
daily_reset_at string ISO 8601 timestamp when the daily counter resets.
Errors:
400 invalid_request Invalid JSON body or field values
402 payment_required x402 payment needed
403 forbidden Caller does not own this wallet
404 not_found Wallet not found
---
### POST /v1/wallets/:address/pause
Pause operations for a wallet. Temporarily halts spending without deactivating.
Price: $0.001
Path params:
address string required address parameter
Request:
scope PauseScope optional Scope to pause. "all" | "send" | "swap". Default "all".
Response (200):
wallet_address string Wallet address that was paused.
paused boolean Always true on success.
scope PauseScope Scope that was paused.
paused_at string ISO 8601 timestamp when the wallet was paused.
Errors:
400 invalid_request Invalid scope value
402 payment_required x402 payment needed
403 forbidden Caller does not own this wallet
404 not_found Wallet not found
---
### POST /v1/wallets/:address/resume
Resume operations for a paused wallet
Price: $0.001
Path params:
address string required address parameter
Request:
scope PauseScope optional Scope to resume. "all" | "send" | "swap". Default "all".
Response (200):
wallet_address string Wallet address that was resumed.
paused boolean Always false on success (wallet is unpaused).
scope PauseScope Scope that was resumed.
resumed_at string ISO 8601 timestamp when the wallet was resumed.
Errors:
400 invalid_request Invalid scope value
402 payment_required x402 payment needed
403 forbidden Caller does not own this wallet
404 not_found Wallet not found
---
## Ownership
All resources scoped to the wallet address extracted from the x402 payment signature. Wallet registration uses EIP-191 signature for ownership proof.