d402distributed 402
For applications and agents

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.

discovery
GET https://gateway.example/.well-known/d402-gateway.json
  • Check capabilities for web.page_to_markdown@1 or another service you need.
  • Check endpoints.capabilities if you want to query signed capability registrations directly.
  • Check payment for x402, Solana direct, escrow, or channel support.
  • Check trust.agent if 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.

capability search
  • 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.

d402-agent
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.

web to markdown
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.

RailUse whenRetry proof
x402 on BaseYou want standards-compatible USDC payment.PAYMENT-SIGNATURE
Solana directYou want very low-cost one-off USDC payment.Authorization: Payment ...
Solana channelYou 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.

accepted response
{
  "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

requestMarkdown.js
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();
}