get402 / docs

get402 docs

Fetch a public URL and return its main content as markdown.

Price

0.005 USDC per successful call on base, paid to 0xB3b5Fb04B2Aef15baf18b121F49fF1DfD100Dd2E over x402. You pay only when you get a 200 with markdown. Every error is free.

How a call works

  1. Call GET https://get402.ai/v1/fetch?url=… with no payment. The answer is 402 with a PAYMENT-REQUIRED header: base64 JSON, x402 version 2.
  2. Sign one of its accepts entries with your wallet and repeat the call with the result in a PAYMENT-SIGNATURE header. Any stock x402 v2 client does this for you.
  3. The proof is verified, the page is fetched, and settlement happens only if the answer is 200. That 200 carries a PAYMENT-RESPONSE header, base64 JSON with the settlement transaction, the same record as meta.payment. Sending the same proof again returns the same response and does not charge you twice.

Paying from code

Tested against this service with the stock x402 client @x402/fetch 2.28.0 and @x402/evm 2.28.0, set up as its README shows:

import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY);
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
});

const response = await fetchWithPayment("https://get402.ai/v1/fetch?url=https://example.com/page");
const { data, error, meta } = await response.json();

Parameters

NameRequiredMeaning
urlyesAbsolute http or https URL to fetch.
freshno1 or true bypasses the cache and fetches now. Same price.
max_bytesnoCap on the downloaded body size. The server enforces its own maximum regardless.
timeout_msnoHint. The server enforces its own upper bound.

Example 402 challenge

The decoded PAYMENT-REQUIRED header this host sends for ?url=https://example.com/page.

Show the challenge
{
  "x402Version": 2,
  "error": "Payment required",
  "resource": {
    "url": "https://get402.ai/v1/fetch?url=https://example.com/page",
    "description": "Fetch a public URL and return its main content as markdown.",
    "mimeType": "application/json"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "amount": "5000",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "payTo": "0xB3b5Fb04B2Aef15baf18b121F49fF1DfD100Dd2E",
      "maxTimeoutSeconds": 300,
      "extra": {
        "name": "USD Coin",
        "version": "2"
      }
    }
  ],
  "extensions": {
    "bazaar": {
      "info": {
        "input": {
          "type": "http",
          "method": "GET",
          "queryParams": {
            "url": "https://example.com/page"
          }
        },
        "output": {
          "type": "json",
          "example": {
            "method": "GET",
            "path": "/v1/fetch",
            "params": [
              {
                "name": "url",
                "required": true,
                "description": "Absolute http or https URL to fetch."
              },
              {
                "name": "fresh",
                "required": false,
                "description": "1 or true bypasses the cache and fetches now. Same price."
              },
              {
                "name": "max_bytes",
                "required": false,
                "description": "Cap on the downloaded body size. The server enforces its own maximum regardless."
              },
              {
                "name": "timeout_ms",
                "required": false,
                "description": "Hint. The server enforces its own upper bound."
              }
            ],
            "price": {
              "amount": "0.005",
              "asset": "USDC",
              "network": "base",
              "payTo": "0xB3b5Fb04B2Aef15baf18b121F49fF1DfD100Dd2E"
            },
            "example_success": {
              "data": {
                "url": "https://example.com/page",
                "final_url": "https://example.com/page",
                "title": "Page title",
                "description": null,
                "content_type": "text/html; charset=utf-8",
                "markdown": "# Page title\n\nExample body.",
                "word_count": 5,
                "truncated": false,
                "fetched_at": "2026-09-19T12:00:00.000Z"
              },
              "error": null,
              "meta": {
                "request_id": "00000000-0000-4000-8000-000000000001",
                "cost_usdc": "0.005",
                "cached": false,
                "cached_at": null,
                "upstream_status": 200,
                "payment": {
                  "network": "base",
                  "asset": "USDC",
                  "payer": "0x1111111111111111111111111111111111111111",
                  "settlement_ref": "0x1111111111111111111111111111111111111111111111111111111111111111"
                }
              }
            },
            "example_error": {
              "data": null,
              "error": {
                "code": "blocked_target",
                "message": "Private, link-local and metadata addresses are not fetchable."
              },
              "meta": {
                "request_id": "00000000-0000-4000-8000-000000000002",
                "cost_usdc": "0",
                "cached": false,
                "cached_at": null,
                "upstream_status": null,
                "payment": null
              }
            },
            "errors": [
              {
                "code": "payment_required",
                "status": 402,
                "when": "No payment proof was sent.",
                "message": "Payment is required."
              },
              {
                "code": "payment_invalid",
                "status": 402,
                "when": "A proof was sent but verification failed.",
                "message": "The payment proof could not be verified."
              },
              {
                "code": "invalid_url",
                "status": 400,
                "when": "Missing, relative, or malformed url.",
                "message": "The url parameter must be an absolute http or https URL."
              },
              {
                "code": "blocked_target",
                "status": 400,
                "when": "Non-http(s) scheme, a private, link-local, or metadata address, or a host on the deny list, at any redirect hop.",
                "message": "Private, link-local and metadata addresses are not fetchable."
              },
              {
                "code": "blocked_by_robots",
                "status": 403,
                "when": "robots.txt disallows the get402 user agent for the path.",
                "message": "The target's robots.txt disallows this user agent for that path."
              },
              {
                "code": "rate_limited",
                "status": 429,
                "when": "Per-caller, per-target-host, or per-payer limit hit. Retry-After gives the seconds to wait. Never charged.",
                "message": "Rate limit exceeded."
              },
              {
                "code": "upstream_failed",
                "status": 502,
                "when": "DNS, connect, TLS, or read failure. A timeout uses the same code with HTTP 504.",
                "message": "The upstream request failed before a response."
              },
              {
                "code": "upstream_error",
                "status": 502,
                "when": "The target answered with 4xx or 5xx. meta.upstream_status carries that status.",
                "message": "The target returned an error."
              },
              {
                "code": "too_large",
                "status": 422,
                "when": "The hard cap was hit before extraction could succeed.",
                "message": "The body exceeded the size cap before enough content was read to extract."
              },
              {
                "code": "unsupported_content",
                "status": 422,
                "when": "The body is not HTML or plain text.",
                "message": "Only HTML and plain text can be extracted."
              },
              {
                "code": "extraction_empty",
                "status": 422,
                "when": "The fetch succeeded but extraction found no article body.",
                "message": "The page had no usable main content."
              },
              {
                "code": "not_found",
                "status": 404,
                "when": "Unknown request_id on the receipts route.",
                "message": "No request exists with that id."
              },
              {
                "code": "unavailable",
                "status": 503,
                "when": "Health check failed. error.message names the dependency.",
                "message": "A dependency is unavailable."
              },
              {
                "code": "internal",
                "status": 500,
                "when": "Unexpected failure in this service.",
                "message": "get402 failed while handling the request."
              }
            ]
          }
        }
      },
      "schema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
          "input": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "http"
              },
              "method": {
                "type": "string",
                "enum": [
                  "GET",
                  "HEAD",
                  "DELETE"
                ]
              },
              "queryParams": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Absolute http or https URL to fetch."
                  },
                  "fresh": {
                    "type": "string",
                    "description": "1 or true bypasses the cache and fetches now. Same price."
                  },
                  "max_bytes": {
                    "type": "string",
                    "description": "Cap on the downloaded body size. The server enforces its own maximum regardless."
                  },
                  "timeout_ms": {
                    "type": "string",
                    "description": "Hint. The server enforces its own upper bound."
                  }
                },
                "required": [
                  "url"
                ]
              }
            },
            "required": [
              "type",
              "method"
            ],
            "additionalProperties": false
          },
          "output": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string"
              },
              "example": {
                "type": "object"
              }
            },
            "required": [
              "type"
            ]
          }
        },
        "required": [
          "input"
        ]
      }
    }
  }
}

Example 200

{
  "data": {
    "url": "https://example.com/page",
    "final_url": "https://example.com/page",
    "title": "Page title",
    "description": null,
    "content_type": "text/html; charset=utf-8",
    "markdown": "# Page title\n\nExample body.",
    "word_count": 5,
    "truncated": false,
    "fetched_at": "2026-09-19T12:00:00.000Z"
  },
  "error": null,
  "meta": {
    "request_id": "00000000-0000-4000-8000-000000000001",
    "cost_usdc": "0.005",
    "cached": false,
    "cached_at": null,
    "upstream_status": 200,
    "payment": {
      "network": "base",
      "asset": "USDC",
      "payer": "0x1111111111111111111111111111111111111111",
      "settlement_ref": "0x1111111111111111111111111111111111111111111111111111111111111111"
    }
  }
}

Example error

{
  "data": null,
  "error": {
    "code": "blocked_target",
    "message": "Private, link-local and metadata addresses are not fetchable."
  },
  "meta": {
    "request_id": "00000000-0000-4000-8000-000000000002",
    "cost_usdc": "0",
    "cached": false,
    "cached_at": null,
    "upstream_status": null,
    "payment": null
  }
}

Error codes

CodeHTTPWhen
payment_required402No payment proof was sent.
payment_invalid402A proof was sent but verification failed.
invalid_url400Missing, relative, or malformed url.
blocked_target400Non-http(s) scheme, a private, link-local, or metadata address, or a host on the deny list, at any redirect hop.
blocked_by_robots403robots.txt disallows the get402 user agent for the path.
rate_limited429Per-caller, per-target-host, or per-payer limit hit. Retry-After gives the seconds to wait. Never charged.
upstream_failed502DNS, connect, TLS, or read failure. A timeout uses the same code with HTTP 504.
upstream_error502The target answered with 4xx or 5xx. meta.upstream_status carries that status.
too_large422The hard cap was hit before extraction could succeed.
unsupported_content422The body is not HTML or plain text.
extraction_empty422The fetch succeeded but extraction found no article body.
not_found404Unknown request_id on the receipts route.
unavailable503Health check failed. error.message names the dependency.
internal500Unexpected failure in this service.

Machine-readable

Upstream behavior

The fetcher identifies itself, honors robots.txt, and refuses private addresses. What site owners can expect, and how to opt out, is on the policy page.