String API
Get Started

Agentic payments (x402)

Let an AI agent pay for each request in USDC over x402, with no String account or API key.

String Web Access accepts the x402 protocol, so an AI agent can pay for a request by itself. It needs no String account, API key, or prepaid balance. It calls the API, gets a price back, pays in USDC, and receives the response.

x402 is for software that pays for itself. An agent working for a team that already has a String account should use an API key instead, which bills the account balance at plan rates.

How it works

x402 turns the HTTP 402 Payment Required status into a challenge and response:

┌──────────────┐                            ┌────────────────────────┐
│   AI agent   │ ── POST /v1/fetch ───────▶ │  request.usestring.ai  │
│  (wallet     │                            │                        │
│  with USDC)  │ ◀── 402 + price ────────── │                        │
│              │                            │                        │
│              │ ── POST /v1/fetch ───────▶ │                        │
│              │    + signed payment        │                        │
│              │                            │                        │
│              │ ◀── 200 + response ─────── │                        │
│              │     + receipt              │                        │
└──────────────┘                            └────────────────────────┘
  1. The agent sends an ordinary request with no Authorization header.
  2. String answers 402 Payment Required. The PAYMENT-REQUIRED header offers two ways to pay, both capped at $0.006, with the network, token, and recipient, as base64-encoded JSON.
  3. The agent's x402 client picks an option it supports and signs a USDC authorization for it.
  4. The agent sends the same request again, with the signed payment in the PAYMENT-SIGNATURE header.
  5. String verifies the payment and runs the request. If the request succeeds, String settles the payment and returns the response with a PAYMENT-RESPONSE header, a base64-encoded receipt that includes the on-chain transaction hash.

An x402 client such as purl or @x402/fetch handles steps 2 to 4 for you.

Failed requests are not charged

String settles a payment only after the request succeeds. If the API answers with a status of 400 or above, the payment is never submitted and no USDC leaves the wallet. An error from the site itself, such as a 409, comes back inside a 200 and is charged like any other fetch.

Pricing

POST /v1/fetch accepts x402. The request body is the same as with an API key; see the Fetch reference. Every other endpoint still requires an API key, including browser sessions over /v1/wss.

The challenge lists two payment schemes, upto first:

SchemeWhat a request costsClients
uptoThe Starter rate for the path the fetch took, at most $0.006@x402/fetch with UptoEvmScheme
exactA flat $0.006Any x402 client, including purl

Under upto, the charge depends on the fetch path and proxy class the API selects:

Fetch pathProxy classPer request
Request-based fetchStandard proxy$0.0003
Request-based fetchPremium proxy$0.003
Browser-based fetchStandard proxy$0.0015
Browser-based fetchPremium proxy$0.006

These are the Starter plan's per-request rates from Pricing.

Three fetch options need an API key, because their cost can exceed $0.006: jsonSchema, actions, and screenshot. A keyless request that uses one gets a 400 before any payment is requested.

Network and token

SettingValue
NetworkBase (eip155:8453) TBD
TokenUSDC
Schemesupto, exact

The wallet only needs USDC. The x402 facilitator submits the transfer on-chain and pays the gas, so the agent doesn't need ETH.

Get started

Option 1: purl on the command line

purl is Stripe's curl-style client for paid HTTP requests. It pays with the exact scheme, so each request costs a flat $0.006.

# Install purl
brew install stripe/purl/purl

# Create or import a wallet
purl wallet add

Fund the wallet with USDC on Base from an exchange or a bridge. Keep a separate wallet for agent spending.

# Show the price without paying
purl --dry-run --json '{"url":"https://example.com","format":"markdown"}' https://request.usestring.ai/v1/fetch

# Pay and fetch
purl --json '{"url":"https://example.com","format":"markdown"}' https://request.usestring.ai/v1/fetch

--json sends the body as a POST with a JSON content type. To cap what purl will pay, add --max-amount with the limit in USDC's smallest unit. USDC has six decimals, so --max-amount 6000 refuses any price above $0.006. purl balance shows what is left in the wallet.

Option 2: TypeScript with @x402/fetch

@x402/fetch wraps fetch, so a 402 is paid and the request retried without extra code. Register the upto scheme to pay the actual Starter rate. It reads the wallet's token approvals over RPC, so give it a Base RPC URL.

npm install @x402/fetch @x402/evm viem
import { decodePaymentResponseHeader, wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { UptoEvmScheme } from "@x402/evm/upto/client";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);

const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [
    {
      network: "eip155:8453",
      client: new UptoEvmScheme(account, { rpcUrl: "https://mainnet.base.org" })
    }
  ]
});

const response = await fetchWithPayment("https://request.usestring.ai/v1/fetch", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ url: "https://example.com", format: "markdown" })
});

console.log(await response.text());

const receipt = response.headers.get("PAYMENT-RESPONSE");
if (receipt) console.log(decodePaymentResponseHeader(receipt));

To pay the flat $0.006 instead, register ExactEvmScheme from @x402/evm. Load the private key from the environment, and never commit it.

Responses

StatusHeaderMeaning
402PAYMENT-REQUIREDNo payment was attached, or the payment was rejected, for example because the wallet holds too little USDC. The header carries the price options and the reason; pay again.
402PAYMENT-RESPONSEThe payment was accepted but failed to settle on-chain. The receipt in the header has success: false and the reason.
200PAYMENT-RESPONSEPaid and served. The header is the settlement receipt.
400—Invalid input, or jsonSchema, actions, or screenshot sent without an API key. No payment is requested.
403—The destination or path needs approval. The reason says to create a String account and complete KYC. Nothing is charged.
429Retry-AfterA rate limit was reached; see Notes.
Any other status of 400 or more—The request failed and nothing was charged. See Errors.

Notes

  • Each request is paid on its own. There is no balance, so nothing carries over from one call to the next.
  • A request that sends an Authorization header is billed to its account as usual and never goes through x402.
  • Without a payment, each IP gets 5 requests a minute, and failed payments count toward that. Paid requests are limited to 10 a second per wallet.
  • Captcha solving is off for x402 requests. A page that needs one fails, and nothing is charged.

Claude skill

Add the skill below to Claude Code. When you ask Claude to read a URL, it fetches the page through String and pays for it over x402.

Create the skill folder

From your project root:

mkdir -p .claude/skills/string-x402

Add SKILL.md

Save the contents below as .claude/skills/string-x402/SKILL.md.

Set up purl

Claude pays through purl, so install it and fund a wallet as in Option 1.

Ask Claude to fetch a page

Claude Code loads the skill on its own. Ask it to read a URL, and it calls String through purl.

---
name: string-x402
description: Fetch web pages through String Web Access and pay for each request with x402 (USDC on Base) using purl. Use when asked to read, fetch, or scrape a URL, especially a site that blocks bots.
---

# String Web Access over x402

String fetches any URL, including sites behind bot protection or JavaScript rendering, and
returns it as Markdown or JSON. Each request is paid with x402 through `purl`, so no API key is
needed.

## Endpoint

`POST https://request.usestring.ai/v1/fetch`, $0.006 per request through `purl`.

Body: `{"url": "https://example.com", "format": "markdown"}`

- `format`: `markdown` is best for reading; `json` (the default) and `raw` are also available.
- `mainContentOnly: true` strips navigation, headers, and footers from Markdown.
- `executeJS: true` renders the page in a browser first.
- `jsonSchema`, `actions`, and `screenshot` need an API key. Don't send them.

All parameters: https://portal.usestring.ai/docs/api-reference/fetch

## Calling it

```bash
purl --json '{"url":"https://example.com","format":"markdown"}' https://request.usestring.ai/v1/fetch
```

- Add `--dry-run` to see the price without paying.
- Add `--max-amount 6000` to refuse anything above $0.006. USDC has six decimals.
- A `402` after paying means the payment failed. Check the wallet with `purl balance`.
- A `403` means the site needs an approved String account. Tell the user rather than retrying.
- Failed requests, with a status of 400 or above, are not charged.

## Cost and etiquette

Every successful fetch is paid. Fetch the page you need rather than crawling around it, and don't
re-fetch a URL you already have in context.