Skip to main content

1claw pay

The x402 guide covers being on the receiving end of a 402 — paying 1Claw for overages. This is the other direction: your agent hits somebody else's paywall and needs to pay it.

1claw pay --agent research-bot https://api.example.com/premium
  402 │ $0.001 → 0x2B62…8Abc
Authorize: https://1claw.co/cli/pay-authorize?session=…
✔ Authorized
signed │ $0.001
200 │ paid

What holds the money still

The CLI holds the network connection and nothing else. It sends the vault the exact bytes the paywall served; the vault decides what may be signed, what you are shown, and what the daily ledger says.

That division is the whole design:

  • The digest binds the transfer, not the ceiling. An x402 challenge's maxAmountRequired is what the origin will accept. What leaves the wallet may be less, and it is that value the digest and the authorize page bind — so what you approve and what gets signed cannot drift apart.
  • The raw challenge is the preimage. The CLI never parses the 402 into fields and sends those; anything reinterpreted first would fall outside what you actually approved.
  • Keys never leave the vault. You get an X-PAYMENT header back, never key material.

Turning it on

Pay is off until a human turns it on, and an agent cannot turn it on for itself.

curl -X PATCH https://api.1claw.co/v1/agents/$AGENT_ID/pay/settings \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"pay_enabled": true,
"pay_max_usd": "1.00",
"pay_daily_limit_usd": "10.00"
}'

The agent also needs an Ethereum signing key funded with USDC on Base:

curl -X POST https://api.1claw.co/v1/agents/$AGENT_ID/signing-keys \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"chain": "ethereum"}'

The three modes

--mode is a request. The vault honours it only where the agent's own policy already allows it.

ModeWhat it asks for
strict (default)A passkey touch for each payment.
sessionOne touch creates a capped, time-bounded grant; payments inside it need no further prompt.
autoNo ceremony. Only reachable for an agent explicitly configured to run unattended.

When each is allowed

pay_require_passkey defaults to true, and while it is true every payment needs a human touch. An allowlisted recipient does not bypass that — the allowlist only widens which recipients a grant may cover.

pay_require_passkeypayTo allowlistedRequestedResult
trueeitherstrictPasskey for this payment
trueeithersessionPasskey creates a grant
trueeitherautoRefused as auto; degraded to the ceremony the agent is configured for
falseyesanySigned if under caps
falsenoanyDenied — unattended and unlisted

An agent with pay_require_passkey: false and no allowlist pays nobody. A null allowlist is not a wildcard; for an unattended agent it means no one.

Spending grants

A grant is "allow this agent to spend up to $5 for 15 minutes". It is created by a human, over a passkey assertion covering exactly those terms, and it cannot exceed the agent's own pay_grant_max_usd or pay_grant_max_ttl_secs — a grant is a delegation inside limits already set, never a way around them.

1claw pay --mode session --agent research-bot https://api.example.com/premium

The cap is decremented as payments are signed, in a single guarded statement, so two concurrent payments cannot both spend the last dollar. Revoke early:

curl -X DELETE https://api.1claw.co/v1/pay-grants/$GRANT_ID \
-H "Authorization: Bearer $USER_TOKEN"

Limits are charged at signing

A payment counts against pay_daily_limit_usd the moment it is signed, not when it settles. A signature that was produced and then lost still consumed authority — the paywall may yet present it.

Reporting a failure afterwards does not give the headroom back. The response says so explicitly:

{ "recorded": "signed_failed", "limit_released": false }

Only a vault-verified reconciliation can return headroom, and that is not built yet. "The payment failed, let me spend again" is the one claim a client must not be able to make.

When the challenge window closes

Many paywalls give you seconds. If the window closes before you authorize, the CLI re-fetches the resource for a fresh 402 rather than re-using the one it has — the stored bytes would reproduce the same closed window, and many challenges carry a single-use nonce.

It tries twice, then stops:

The paywall's challenge window closed 2 times before the payment could be authorized.
Its window is likely too short for a per-payment approval. Try again, or use a
spending grant (--mode session) so payments inside the window need no prompt.

prepare also flags a window under 30 seconds up front, so you know before you open the authorize page.

Trying it without spending anything

The x402-pay-cli example runs a mock paywall locally:

node paywall.mjs &
ONECLAW_PAY_DEV=1 1claw pay --agent any http://localhost:4022/premium

The dev signer never contacts the vault and produces a header no paywall would honour — it exercises the flow without ever being mistakable for a real payment.

What can be paid

Two schemes, chosen by the chain rather than by a flag — EIP-3009 is an ERC-20 extension that does not exist on Solana, and an SPL transfer is not something an EVM paywall settles.

NetworkAssetsScheme
BaseUSDC, USDbCEIP-3009
Base SepoliaUSDCEIP-3009
OptimismUSDC, USDTEIP-3009
AvalancheUSDC, USDTEIP-3009
BNB ChainUSDC, USDT (18 decimals)EIP-3009
SolanaUSDC, USDTsigned SPL transfer
Solana devnetUSDCsigned SPL transfer

Every address and mint above was verified on-chain by reading symbol() and decimals() (or getTokenSupply on Solana). An asset that is not listed is refused, not guessed at — the daily limit is denominated in USD, and a fabricated rate would go both in front of you and into the ledger.

A challenge may name its network as base, eip155:8453 or a bare chain id; all three resolve. Assets may be named by contract address, SPL mint, or symbol — but a symbol only resolves within the stated network, because the same symbol is a different token on every chain.

Ethereum, Arbitrum and Polygon are absent on purpose. Their addresses could not be verified on-chain when the table was written, and a plausible-looking guess is worse than a refusal: a wrong address signs a transfer of the wrong token.

Tron, XRPL, Cardano and Bitcoin cannot be paid at all — no x402 scheme exists for them here. They fail with that reason rather than a pricing one, so you are not sent looking for a price oracle you do not need.

Limits today

  • Signing happens in the vault, not yet in the Shroud TEE.
  • No reconciliation, so limit headroom is never returned automatically.
  • The Solana payload envelope is unverified against a live facilitator. The transfer is built and signed correctly; whether a given facilitator expects exactly that JSON has not been tested against a real Solana x402 endpoint.
  • The /cli/pay-authorize page does not exist yet, so the strict-mode browser flow cannot complete. Unattended mode (pay_require_passkey: false plus an allowlisted payTo) works today.

Endpoints

EndpointWho
POST /v1/agents/{id}/pay/prepareAgent or human
POST /v1/agents/{id}/pay/signAgent or human, plus authorization
POST /v1/agents/{id}/pay/{payment_id}/resultAgent or human
GET /v1/agents/{id}/pay/{payment_id}Agent or human
PATCH /v1/agents/{id}/pay/settingsHuman only
POST /v1/agents/{id}/pay/grantsHuman only, plus a passkey assertion
GET /v1/pay-sessions/{id}The human it was raised for
POST /v1/pay-sessions/{id}/authorizeThe human it was raised for
DELETE /v1/pay-grants/{id}Human only

A pay session is readable only by the person who must authorize it — not an agent, and not another member of the same org. The response decides whether a payment may be signed, and a session id is not authorization.