Connect to d402 and buy work.
Your app does not need to join the peer network. It calls one or more HTTP gateways, handles a payment challenge, and receives structured results, receipts, and evidence.
1. Discover a gateway
Start with a gateway URL you trust. The gateway document tells your software what capabilities, directory endpoints, prices, payment rails, and task endpoints are available.
GET https://gateway.example/.well-known/d402-gateway.json
- Check
capabilitiesforweb.page_to_markdown@1or another service you need. - Check
endpoints.capabilitiesif you want to query signed capability registrations directly. - Check
paymentfor x402, Solana direct, escrow, or channel support. - Check
trust.agentif you require a gateway trust passport.
2. Choose a capability
Software should treat a capability as a contract with the network: a stable ID, version, manifest CID, schemas, validator policy, evidence requirements, and pricing unit. The same gateway can expose built-in services and permissionlessly registered third-party capabilities.
GET https://gateway.example/capabilities?tag=commerce GET https://gateway.example/capabilities?namespace=example GET https://gateway.example/capabilities?manifestCid=sha256:...
- For routine traffic, require an active manifest CID and a worker offer pinned to that CID.
- For high-value traffic, require signed registration envelopes, wallet namespace proofs, accepted manifest policy, and non-deprecated versions.
- For new capability families, inspect the validator marketplace and confirm at least one independent validator can score the output.
3. Use the Agent CLI
The reference buyer client is d402-agent. It owns local buyer config, gateway discovery, capability search, max-payment policy, payment-aware task requests, receipt caching, signer plugins, and a local daemon mode so application code does not need to reimplement the 402 loop.
npm install -g github:namistaken/dnc d402-agent init --gateway https://gateway.example --rail manual d402-agent discover d402-agent capabilities --tag web d402-agent request --url https://example.com --rail manual d402-agent ledger --limit 20 d402-agent verify-receipt --task-id task:... d402-agent update check --manifest release.json --trusted-key-file release-key.json d402-agent daemon --host 127.0.0.1 --port 7402
Production buyers should bring their own wallet or signer. The CLI can explicitly provision a local EVM hot wallet for capped testing, sign Solana channel debits from a local keypair, call a remote signer plugin, or read secrets from macOS Keychain. Updates are explicit and threshold-signed; the Agent verifies release metadata and artifact hashes before staging anything.
4. Create a task
The first d402 service accepts a URL and returns markdown. Public gateways may ignore client-supplied pricing and routing policy; server-owned policy keeps the service safe.
POST https://gateway.example/tasks
Content-Type: application/json
{
"input": {
"url": "https://example.com"
},
"sync": true
}5. Handle HTTP 402
If the task requires payment, the gateway returns 402 Payment Required. Your payment agent signs or submits the required payment, then retries the same task body idempotently.
| Rail | Use when | Retry proof |
|---|---|---|
| x402 on Base | You want standards-compatible USDC payment. | PAYMENT-SIGNATURE |
| Solana direct | You want very low-cost one-off USDC payment. | Authorization: Payment ... |
| Solana channel | You make many small requests over time. | Buyer-signed channel debit |
6. Store results and evidence
A successful response includes the result, validation receipt, settlement receipt, selected capability, manifest CID, and links for follow-up lookup. High-value buyers can require portable trust bundles and external anchor verification before routing work.
{
"taskId": "task:...",
"status": "accepted",
"capabilityId": "web.page_to_markdown",
"manifestCid": "sha256:...",
"result": {
"title": "Example Domain",
"markdown": "# Example Domain\n\n..."
},
"validationReceipt": {},
"settlement": {},
"links": {
"result": "/tasks/task-id/result",
"receipt": "/tasks/task-id/receipt"
}
}Minimal client skeleton
export async function requestMarkdown({ gatewayUrl, url, pay }) {
const body = { input: { url }, sync: true };
const first = await fetch(new URL("/tasks", gatewayUrl), {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body)
});
if (first.status !== 402) return first.json();
const challenge = first.headers.get("payment-required")
? JSON.parse(Buffer.from(first.headers.get("payment-required"), "base64").toString("utf8"))
: await first.json();
const paymentHeaders = await pay({ challenge, body });
const paid = await fetch(new URL("/tasks", gatewayUrl), {
method: "POST",
headers: { "content-type": "application/json", ...paymentHeaders },
body: JSON.stringify(body)
});
if (!paid.ok) throw new Error(await paid.text());
return paid.json();
}