{
  "slug": "paying-for-access-402",
  "title": "Paying for Access: The HTTP 402 Flow",
  "description": "How autonomous agents encounter, interpret and satisfy HTTP 402 Payment Required responses on ChangeGamer.",
  "category": "Policy",
  "tags": [
    "402",
    "payments",
    "api-keys",
    "monetization"
  ],
  "updated": "2026-07-08",
  "premium": false,
  "canonical": "https://changegamer.ai/resources/paying-for-access-402",
  "markdown": "https://changegamer.ai/resources/paying-for-access-402.md",
  "outline": [
    {
      "depth": 2,
      "text": "TL;DR for agents",
      "anchor": "tl-dr-for-agents"
    },
    {
      "depth": 2,
      "text": "Which paths can return 402",
      "anchor": "which-paths-can-return-402"
    },
    {
      "depth": 2,
      "text": "Current status — the gate is active",
      "anchor": "current-status-the-gate-is-active"
    },
    {
      "depth": 2,
      "text": "Exact 402 response contract",
      "anchor": "exact-402-response-contract"
    },
    {
      "depth": 2,
      "text": "Purchasing an access key",
      "anchor": "purchasing-an-access-key"
    },
    {
      "depth": 2,
      "text": "GET /key — self-serve key delivery contract",
      "anchor": "get-key-self-serve-key-delivery-contract"
    },
    {
      "depth": 2,
      "text": "Retrying with a key",
      "anchor": "retrying-with-a-key"
    },
    {
      "depth": 2,
      "text": "Summary for agent implementors",
      "anchor": "summary-for-agent-implementors"
    },
    {
      "depth": 2,
      "text": "Native x402 (keyless, on-chain) — buyer walkthrough",
      "anchor": "native-x402-keyless-on-chain-buyer-walkthrough"
    },
    {
      "depth": 3,
      "text": "Today's actual behavior — an exact curl call against the live endpoint",
      "anchor": "today-s-actual-behavior-an-exact-curl-call-against-the-live-endpoint"
    },
    {
      "depth": 3,
      "text": "The documented future contract — NOT live, for when a facilitator + wallet are configured",
      "anchor": "the-documented-future-contract-not-live-for-when-a-facilitator-wallet-are-configured"
    }
  ],
  "related": [
    {
      "slug": "agentic-payment-protocols",
      "title": "Agentic Payment Protocols: 402, Pay Per Crawl, and x402",
      "description": "Implementor's comparison of the three live mechanisms for agent-to-server content payment: self-hosted HTTP 402 gates, Cloudflare Pay Per Crawl, and the x402 open standard — plus how RSL fits as the licensing layer, not the settlement layer.",
      "url": "https://changegamer.ai/resources/agentic-payment-protocols"
    },
    {
      "slug": "selling-to-agents",
      "title": "Selling to Agents: Charging AI Agents for Your API or Content",
      "description": "Seller-side guide to monetizing agent traffic: self-hosted HTTP 402 gates, native x402 with automatic Bazaar listing, marketplace publishing, and crawl licensing — with an honest status ledger from a site that runs these rails in production.",
      "url": "https://changegamer.ai/resources/selling-to-agents"
    },
    {
      "slug": "access-and-pricing",
      "title": "Access & Pricing for Crawlers",
      "description": "Free vs. paid access: four paid tiers from €5 and how agents pay programmatically via HTTP 402.",
      "url": "https://changegamer.ai/resources/access-and-pricing"
    },
    {
      "slug": "agent-wallets-x402",
      "title": "Agent Wallets: Paying Per Run with x402",
      "description": "Buyer-side guide to giving an AI agent a wallet: how the x402 payment loop works, the client libraries that automate it, spend controls, and what 20,000+ Apify Actors on x402 mean for agent tool budgets.",
      "url": "https://changegamer.ai/resources/agent-wallets-x402"
    }
  ],
  "furtherReading": [
    {
      "slug": "agent-checkout-vs-human-checkout",
      "title": "Agent Checkout vs. Human Checkout: Why Your Payment Flow Fails Machine Buyers",
      "description": "Why checkout built for a person watching a screen is unusable by an AI agent, and what a checkout flow that actually completes for a machine buyer looks like — 402 + API key versus native x402.",
      "url": "https://changegamer.ai/articles/agent-checkout-vs-human-checkout"
    },
    {
      "slug": "acp-vs-ap2-vs-x402",
      "title": "ACP vs. AP2 vs. x402: Which Agent Payment Rail Should You Implement?",
      "description": "A decision framework for choosing between ACP, AP2, and x402 (plus the self-hosted 402 gate) — sorted by who your buyer actually is, what you are selling, and what is live versus waitlisted today.",
      "url": "https://changegamer.ai/articles/acp-vs-ap2-vs-x402"
    }
  ],
  "body": "HTTP `402 Payment Required` is the standard status code for paywalled resources. This guide explains exactly how ChangeGamer uses it — what a 402 response looks like, how to buy an access key, how to retry, and which paths can never return 402.\n\n## TL;DR for agents\n\n1. You hit `402` on a premium slug. The JSON body gives you `payment_url`, `price_usd`, and a `preview` (title, description, and section outline) of what is behind the gate.\n2. Buy a key at `payment_url` (€5 one-time starter). Fulfillment is self-serve: Stripe redirects to `/key?session_id=...`, which returns your `cg_` key as JSON.\n3. Retry the original request with `Authorization: Bearer <key>` (or `x-api-key: <key>`). The key is valid until revoked and unlocks the whole premium set.\n\nAlways free, never 402: `/llms.txt`, `/llms-full.txt`, `robots.txt`, the sitemap, `/license.xml`, and the `getting-started` + `access-and-pricing` resources.\n\n## Which paths can return 402\n\nOnly three URL shapes are eligible to return 402, controlled by `SLUG_PATTERNS` in the worker and the `run_worker_first` list in `wrangler.jsonc`:\n\n- `/resources/<slug>` (with or without trailing slash)\n- `/resources/<slug>.md`\n- `/api/resources/<slug>.json`\n\nThe following paths are **asset-served** (they bypass the worker entirely) and **can never be paywalled by code**:\n\n- `/llms.txt` and `/llms-full.txt`\n- `robots.txt`\n- `/sitemap-0.xml` and the sitemap index\n- `/license.xml`\n\n`/api/resources.json` (the corpus index) matches no slug pattern in the worker, so it also cannot return 402.\n\nAdditionally, two slugs are hard-coded as `FREE_SLUGS` in the worker — `getting-started` and `access-and-pricing` — which means adding them to the premium list has no effect; they always pass through for free.\n\n## Current status — the gate is active\n\nThe premium set currently contains [Data Formats & Schema](/resources/data-formats), [JSON API for Agents](/resources/json-api), and [How ChangeGamer Runs Itself](/resources/autonomous-operations); requests to those slugs without a valid key return 402. All other resources are free. The authoritative, always-current premium list is announced on the `access-and-pricing` resource whenever it changes.\n\n## Exact 402 response contract\n\nWhen a request hits a premium slug without a valid key, the worker returns:\n\n```\nHTTP/1.1 402 Payment Required\nContent-Type: application/json; charset=utf-8\nLink: <https://buy.stripe.com/fZu9AMa230eP2b1f0d7EQ00>; rel=\"payment\", <https://changegamer.ai/license.xml>; rel=\"license\", <https://changegamer.ai/api/pricing.json>; rel=\"pricing\"\nCache-Control: no-store\n\n{\n  \"error\": \"payment_required\",\n  \"resource\": \"<slug>\",\n  \"price_usd\": \"0.05\",\n  \"payment_url\": \"https://buy.stripe.com/fZu9AMa230eP2b1f0d7EQ00\",\n  \"how_to_pay\": \"Buy an access key at payment_url, then retry with header 'Authorization: Bearer <key>'. Index files (/llms.txt) and the getting-started and access-and-pricing resources are always free.\",\n  \"terms\": \"https://changegamer.ai/resources/access-and-pricing.md\",\n  \"license\": \"https://changegamer.ai/license.xml\",\n  \"pricing_catalog\": \"https://changegamer.ai/api/pricing.json\",\n  \"preview\": {\n    \"title\": \"<resource title>\",\n    \"description\": \"<one-line resource summary>\",\n    \"sections\": [\"<## heading>\", \"...\"]\n  }\n}\n```\n\nThe JSON keys are, in order: `error`, `resource`, `price_usd`, `payment_url`, `how_to_pay`, `terms`, `license`, `pricing_catalog`, `preview`. The `preview` object holds the resource title, one-line description, and its `##` section-heading outline (no paywalled body prose).\n\n**Note on `price_usd`:** this field represents the per-fetch reference price in USD used by the worker (currently `\"0.05\"`). The access key itself is sold in EUR — a €5.00 one-time starter key. The two figures are distinct: `price_usd` is the per-request accounting unit; €5 is the key purchase price. The field name is not a bug; do not treat them as the same currency.\n\n## Purchasing an access key\n\nA starter key costs **€5.00** (one-time, EUR). Purchase at:\n\nhttps://buy.stripe.com/fZu9AMa230eP2b1f0d7EQ00\n\nFulfillment is **self-serve and automatic**:\n\n1. Pay at https://buy.stripe.com/fZu9AMa230eP2b1f0d7EQ00\n2. Stripe redirects you to `https://changegamer.ai/key?session_id={CHECKOUT_SESSION_ID}`\n3. That URL returns JSON containing your `cg_` access key.\n\nEmail fallback: reply to your Stripe receipt email if the self-serve flow does not resolve.\n\n## GET /key — self-serve key delivery contract\n\nEndpoint: `GET https://changegamer.ai/key?session_id=<cs_live_...>`\n\nAll responses carry `Cache-Control: no-store` (worker/index.ts lines 357, 371, 382, 390, 405, 433). The `session_id` must match `cs_(live|test)_[A-Za-z0-9]+` and be ≤200 chars; otherwise the endpoint returns 400.\n\n**200 — key ready** (worker/index.ts lines 421–435):\n\n```json\n{\n  \"key\": \"cg_<40 hex chars>\",\n  \"created\": \"<ISO-8601 timestamp>\",\n  \"tier\": \"starter\",\n  \"usage\": {\n    \"header_bearer\": \"Authorization: Bearer cg_...\",\n    \"header_api_key\": \"x-api-key: cg_...\",\n    \"instructions\": \"https://changegamer.ai/resources/paying-for-access-402.md\"\n  }\n}\n```\n\n**404 — not found yet** (worker/index.ts lines 395–407): `{\"error\":\"not_found\", \"message\":\"...\"}`. The webhook delivery may lag the payment redirect by a few seconds — wait a moment and retry. The session→key mapping is retained for 30 days (`expirationTtl: 2592000`, worker/index.ts line 325).\n\n**400 — bad or missing session_id** (worker/index.ts lines 366–385): missing `session_id` parameter, or value that fails the format check.\n\nDo not cache any `/key` response. The webhook endpoint `POST https://changegamer.ai/webhooks/stripe` is Stripe-facing; its internals are not documented here beyond its existence.\n\n## Retrying with a key\n\nThe worker checks for a key in this order (first match wins):\n\n1. `Authorization: Bearer <key>` header — preferred. The scheme check is case-insensitive; the key is trimmed of whitespace.\n2. `x-api-key: <key>` header — accepted as a fallback.\n\nExample retry:\n\n```\nGET /resources/some-premium-slug HTTP/1.1\nHost: changegamer.ai\nAuthorization: Bearer cg_your_key_here\n```\n\nOr alternatively:\n\n```\nGET /resources/some-premium-slug HTTP/1.1\nHost: changegamer.ai\nx-api-key: cg_your_key_here\n```\n\nA valid key causes the worker to fall through to static asset delivery — the resource is then served normally with its standard HTTP `200` response.\n\n## Summary for agent implementors\n\n- Check `Cache-Control: no-store` — never cache a 402 response.\n- Read `payment_url` from the JSON body to find the purchase link.\n- Read `how_to_pay` for the retry header format.\n- Check `terms` and `license` links for usage rights.\n- Read `pricing_catalog` to fetch the full four-tier offer catalog (`/api/pricing.json`) and choose a tier.\n- Read `preview` to see the resource title, summary, and section outline — what you are buying before you pay.\n- Free paths (`/llms.txt`, `robots.txt`, `getting-started`, `access-and-pricing`) never need a key; use them freely for discovery.\n\n## Native x402 (keyless, on-chain) — buyer walkthrough\n\nA native x402 endpoint exists at `/api/x402/<slug>` for fully autonomous, keyless, on-chain (USDC) payment — no account, no key purchase. **It is dormant today: every request currently returns HTTP `503` `x402_not_configured`**, because none of the five operator env vars it requires (`X402_FACILITATOR_URL`, `X402_PAY_TO`, `X402_NETWORK`, `X402_ASSET`, `X402_MAX_AMOUNT`) are set on this server. The Bearer-key flow documented above is the live rail. [/api/payment.json](/api/payment.json) is the source of truth for the current status of every payment method — check it before attempting a native x402 call. For the general x402 buyer loop and client libraries (not specific to this site), see [agent wallets](/resources/agent-wallets-x402); this section covers only this endpoint's own request/response contract.\n\n### Today's actual behavior — an exact curl call against the live endpoint\n\nThis works right now and returns 503, not a payment prompt (example slug `data-formats`, currently premium):\n\n```\n$ curl -sS -i https://changegamer.ai/api/x402/data-formats\n\nHTTP/1.1 503 Service Unavailable\nContent-Type: application/json; charset=utf-8\n\n{\n  \"error\": \"x402_not_configured\",\n  \"message\": \"Native x402 on-chain settlement is not yet enabled on this server. Use the HTTP 402 + Bearer key flow or Stripe checkout instead.\",\n  \"fallback\": {\n    \"http_402\": \"https://changegamer.ai/resources/data-formats.md\",\n    \"payment_manifest\": \"https://changegamer.ai/api/payment.json\",\n    \"pricing_catalog\": \"https://changegamer.ai/api/pricing.json\"\n  }\n}\n```\n\n(Calling a non-premium slug instead returns `400 resource_is_free`; an unknown slug returns `404`; a non-`GET` method returns `405` with an `Allow: GET` header. Those checks run first and short-circuit before the config check; for any request that passes them — a valid premium slug, GET method — the 503 above fires next, whether or not an `X-PAYMENT` header is sent.)\n\n### The documented future contract — NOT live, for when a facilitator + wallet are configured\n\nEverything in this subsection is a specification of what the code is built to do once the operator sets all five env vars above. **None are set today; none of the requests below currently work.** Treat every `curl` command and response here as hypothetical, not a claim about current site behavior.\n\n**Step 1 — discovery.** The same call as above, once configured, would draw a `402` instead of a `503`, carrying the payment requirements in `accepts[0]`:\n\n```\n# hypothetical — endpoint is dormant today\n$ curl -sS -i https://changegamer.ai/api/x402/data-formats\n\nHTTP/1.1 402 Payment Required\nContent-Type: application/json; charset=utf-8\n\n{\n  \"x402Version\": 1,\n  \"error\": \"X-PAYMENT header required\",\n  \"accepts\": [\n    {\n      \"scheme\": \"exact\",\n      \"network\": \"<operator-configured, e.g. base>\",\n      \"maxAmountRequired\": \"<operator-configured>\",\n      \"resource\": \"https://changegamer.ai/api/x402/data-formats\",\n      \"description\": \"ChangeGamer premium resource: data-formats\",\n      \"mimeType\": \"text/markdown\",\n      \"payTo\": \"<operator-configured, e.g. a Base wallet address>\",\n      \"maxTimeoutSeconds\": 60,\n      \"asset\": \"<operator-configured, e.g. a USDC contract address>\"\n    }\n  ]\n}\n```\n\nField order in the `accepts[0]` object mirrors the worker's requirements builder exactly; it may also carry an optional trailing `extra: { name, version }` object if the operator sets an asset name (e.g. for EIP-712 domain data). A malformed retry — an `X-PAYMENT` header that is not valid base64-encoded JSON — would draw `400 invalid_x_payment_header` with the same `accepts` array repeated.\n\n**Step 2 — pay and retry.** A client library (see [agent wallets](/resources/agent-wallets-x402) for which ones) signs a payment authorization against the `accepts[0]` requirements, base64-encodes the signed payload, and retries with an `X-PAYMENT` header:\n\n```\n# hypothetical — endpoint is dormant today\n$ curl -sS -i https://changegamer.ai/api/x402/data-formats \\\n    -H \"X-PAYMENT: <base64-encoded signed PaymentPayload JSON>\"\n\nHTTP/1.1 200 OK\nContent-Type: text/markdown; charset=utf-8\nX-PAYMENT-RESPONSE: <base64-encoded settlement receipt JSON>\n\n# Data Formats & Schema\n\n> Structured data conventions: JSON-LD, Markdown variants and stable slugs.\n\n...full resource Markdown body...\n```\n\nThat `200` only happens once the worker's two facilitator calls (`POST <facilitator>/verify`, then `POST <facilitator>/settle`) both succeed. Other outcomes the code defines: the facilitator rejects the payment at `/verify` or `/settle` → `402` with `error` set to its `invalidReason` (falling back to `payment_invalid`) or `errorReason` (falling back to `settlement_failed`); the worker fails to sign its own facilitator-auth request → `502 facilitator_auth_failed`; the facilitator is unreachable or returns something unparseable → `502 facilitator_unreachable`.\n\nOnce again: nothing in this future-contract subsection is reachable today. Confirm the live status of `/api/x402/<slug>` at [/api/payment.json](/api/payment.json) — while its `x402` entry there confirms the same dormant/503 state, the only working call against that path is the `curl` example in \"Today's actual behavior\" above, and it always returns 503.",
  "sources": []
}