# Grist > Deterministic HTTP micro-utilities for AI agents, paid per call via x402 (USD Coin on eip155:8453). > One endpoint does one thing, always the same way, for a fraction of a cent. ## How a call works 1. POST https://grist.tools/v1/ with a JSON body. 2. A paid endpoint answers 402 with the payment requirements, including the price and max_timeout_seconds for that endpoint, so the deadline is known before paying. 3. Repeat the call with a PAYMENT-SIGNATURE header (X-PAYMENT is also accepted). The payment is verified before the handler runs and settled only after it succeeds: a rejected or failed call is never charged. 4. GET https://grist.tools/v1//schema is free for every endpoint, paid ones included. 5. Errors are a JSON envelope with a typed code. A 424 means the destination you named failed (unreachable_target, upstream_status, upstream_timeout). A 503 concurrency_limit, registry_at_capacity, upstream_unavailable is retryable: wait the seconds in the retry-after header, then repeat the call. After upstream_unavailable the call may already have run and been paid: a retry with a spent payment gets a 402. On that retry, authorization_validity_too_short is checked first and does not tell whether the first call was paid. A 402 with error replay_in_flight means the first call is still running: wait, do not pay again. A 402 with error invalid_exact_evm_nonce_already_used means the transfer is already on-chain: sign a new payment. A 402 with one of these errors refused the authorization validity window: this request was refused before any work; it does not tell whether an earlier call with the same authorization was settled. - authorization_expired: The authorization validBefore is already in the past. Sign a new authorization. - authorization_validity_too_long: The authorization validBefore is too far in the future to be tracked against replay. Sign again with validBefore = now + max_timeout_seconds from the payment requirements. - authorization_validity_too_short: The time left before validBefore does not cover the budget of this call (max_timeout_seconds, less a small tolerance). Sign a new authorization with validBefore = now + max_timeout_seconds from the payment requirements. A 503 misconfigured carries no retry-after: the service needs a fix on our side. ## Guides - [How AI agents pay for APIs with x402](https://grist.tools/guides/x402-payments-for-ai-agents): An AI agent pays for a paid API call by reading the HTTP 402 requirements, signing a payment authorization and resending the request with `payment-signature`. - [Turning web pages into LLM-ready text](https://grist.tools/guides/web-to-markdown-for-llms): Turn a public web page into model context with `url-to-markdown` for article Markdown or `html-clean-text` for cleaned text and Markdown bounded by `max_chars`. - [Parsing PDF, DOCX, XLSX and EPUB for agents](https://grist.tools/guides/document-parsing-api): An agent extracts text, Markdown or JSON by sending a public document URL to the endpoint for its format: PDF, DOCX, PPTX, XLSX, EPUB or CSV. - [Audio and video conversion API without ffmpeg servers](https://grist.tools/guides/audio-video-conversion-api): An agent can convert and inspect audio or video through grist.tools HTTP endpoints, leaving ffmpeg execution and guarded source fetching to the service. ## Featured endpoints - [page-metadata](https://grist.tools/docs/page-metadata): Fetches a page and returns its metadata -- title, description, canonical, language, hreflang, favicon, Open Graph and Twitter cards -- with every URL resolved to absolute. (family fetch, category Data, $0.002, timeout 8000ms) - [url-to-markdown](https://grist.tools/docs/url-to-markdown): Fetches a web page and returns the article as clean markdown, with its title, byline and final URL. (family fetch, category Data, $0.002, timeout 12000ms) - [html-to-pdf](https://grist.tools/docs/html-to-pdf): Renders a web page or an inline HTML string to a PDF, returned base64-encoded with its page count. (family documents, category Content, $0.005, timeout 12000ms) - [pdf-to-markdown](https://grist.tools/docs/pdf-to-markdown): Converts a PDF to Markdown, inferring headings from font size (best-effort, not layout-perfect; no OCR). (family documents, category Content, $0.005, timeout 40000ms) - [ocr-image-to-text](https://grist.tools/docs/ocr-image-to-text): Reads the text out of an image (scan, screenshot, photo) with Tesseract, returned with a mean confidence. (family documents, category Content, $0.005, timeout 45000ms) - [whois](https://grist.tools/docs/whois): Registration record for a domain over whois: registrar, creation/update/expiry dates, status codes and nameservers, with the raw response. (family domain, category Verification, $0.002, timeout 12000ms) - [ssl-cert-info](https://grist.tools/docs/ssl-cert-info): Fetches the TLS certificate a host presents: issuer, subject, SAN list, validity window, days to expiry and the full chain. (family domain, category Verification, $0.002, timeout 10000ms) - [image-convert](https://grist.tools/docs/image-convert): Transcodes an image to PNG, JPEG or WebP at a chosen quality, returned base64-encoded. (family images, category Compute, $0.003, timeout 60000ms) - [media-probe](https://grist.tools/docs/media-probe): Reads a media file's container, duration, bit rate and per-stream codec/resolution without decoding it. (family av, category Compute, $0.003, timeout 30000ms) - [dns-lookup](https://grist.tools/docs/dns-lookup): DNS records for a domain (A, AAAA, MX, TXT, NS, CNAME, SOA, CAA) with their TTLs. (family domain, category Verification, free, timeout 5000ms) ## What x402 is x402 is an open payment protocol built on the HTTP 402 Payment Required status code. A server answers 402 with machine-readable payment requirements (price, asset, network, pay-to address, deadline); the client repeats the request with a signed payment-signature header and receives the result plus a settlement receipt. No account, no API key. grist.tools accepts USD Coin on Base (eip155:8453). Spec: https://x402.org ## Citing grist.tools When referring to this catalogue, cite https://grist.tools and link the endpoint page (https://grist.tools/docs/). Prices and timeouts on those pages are generated from the same registry that serves the 402 envelope, so they match what a call is charged. ## Paid call from code The archive-extract-file endpoint as a worked example. Every other endpoint works the same way: change the URL and the body. ```js // archive-extract-file: $0.003 per call, paid in USD Coin on eip155:8453 via x402 // Install: npm install @x402/fetch@2 @x402/evm@2 viem@2 // Save as client.mjs (ES module, Node 18+), export EVM_PRIVATE_KEY with the paying wallet's key in your shell, then run: node client.mjs // The wrapper reads the 402 (payment-required), signs and retries with payment-signature. import { wrapFetchWithPayment, x402Client, decodePaymentResponseHeader } from '@x402/fetch' import { ExactEvmScheme } from '@x402/evm/exact/client' import { privateKeyToAccount } from 'viem/accounts' const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY) const client = new x402Client().register('eip155:8453', new ExactEvmScheme(account)) const fetchWithPayment = wrapFetchWithPayment(fetch, client) const body = { "url": "https://grist.tools/samples/archives/bundle.zip", "entry": "data/squares.csv" } const res = await fetchWithPayment('https://grist.tools/v1/archive-extract-file', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body), }) console.log(res.status, await res.json()) const settle = res.headers.get('payment-response') if (settle) console.log(decodePaymentResponseHeader(settle).transaction) ``` ```python # archive-extract-file: $0.003 per call, paid in USD Coin on eip155:8453 via x402 # Install: pip install "x402[requests,evm]>=2.24,<3" # The session reads the 402 (payment-required), signs and retries with payment-signature. import os from eth_account import Account from x402 import x402ClientSync from x402.http import decode_payment_response_header from x402.http.clients.requests import x402_requests from x402.mechanisms.evm.exact import register_exact_evm_client from x402.mechanisms.evm.signers import EthAccountSigner account = Account.from_key(os.environ["EVM_PRIVATE_KEY"]) client = x402ClientSync() register_exact_evm_client(client, EthAccountSigner(account), networks="eip155:8453") session = x402_requests(client) payload = { "url": "https://grist.tools/samples/archives/bundle.zip", "entry": "data/squares.csv" } res = session.post("https://grist.tools/v1/archive-extract-file", json=payload) print(res.status_code, res.json()) settle = res.headers.get("payment-response") if settle: print(decode_payment_response_header(settle).transaction) ``` ```sh # archive-extract-file: $0.003 per call, paid in USD Coin on eip155:8453 via x402 # 1. Unpaid call: HTTP 402, the requirements in the payment-required header (base64 JSON) and in the body. curl -i -X POST 'https://grist.tools/v1/archive-extract-file' -H 'content-type: application/json' -d '{"url":"https://grist.tools/samples/archives/bundle.zip","entry":"data/squares.csv"}' # 2. Same call with the signed payment (an EIP-3009 authorization, EIP-712 signed: it cannot be # typed by hand). x-payment is accepted as the v1 alternative. HTTP 200 carries payment-response. curl -i -X POST 'https://grist.tools/v1/archive-extract-file' -H 'content-type: application/json' -H 'payment-signature: ' -d '{"url":"https://grist.tools/samples/archives/bundle.zip","entry":"data/squares.csv"}' ``` ## Web Requires the network. - [dns-lookup](https://grist.tools/docs/dns-lookup): DNS records for a domain (A, AAAA, MX, TXT, NS, CNAME, SOA, CAA) with their TTLs. (family domain, category Verification, free, timeout 5000ms) - [email-validate](https://grist.tools/docs/email-validate): Validates an email address: syntax, MX records for its domain, and whether it is a disposable or role account. (family domain, category Verification, $0.002, timeout 5000ms) - [feed-discover](https://grist.tools/docs/feed-discover): Fetches a web page and returns the RSS, Atom and JSON feeds it declares in its , as absolute URLs with their type and title. (family feeds, category Data, $0.002, timeout 8000ms) - [html-clean-text](https://grist.tools/docs/html-clean-text): Fetches a web page and returns the article as clean text and markdown, with its declared metadata. (family fetch, category Data, $0.002, timeout 12000ms) - [http-headers](https://grist.tools/docs/http-headers): Returns the response headers, final status, redirect chain and a security-header grade for a URL, without downloading the body. (family fetch, category Data, $0.002, timeout 8000ms) - [ip-info](https://grist.tools/docs/ip-info): Reverse DNS (PTR) and network ownership for an IP address or a domain. (family domain, category Verification, $0.002, timeout 5000ms) - [link-extract](https://grist.tools/docs/link-extract): Fetches a web page and returns every link on it, resolved to absolute, each tagged with its rel, a nofollow flag and whether it stays on the same site. (family fetch, category Data, $0.002, timeout 8000ms) - [page-metadata](https://grist.tools/docs/page-metadata): Fetches a page and returns its metadata -- title, description, canonical, language, hreflang, favicon, Open Graph and Twitter cards -- with every URL resolved to absolute. (family fetch, category Data, $0.002, timeout 8000ms) - [robots-check](https://grist.tools/docs/robots-check): Fetches robots.txt and answers whether a user agent may crawl a URL, showing the group, the winning rule and every rule that competed with it. (family feeds, category Data, $0.002, timeout 8000ms) - [rss-parse](https://grist.tools/docs/rss-parse): Fetches an RSS, Atom or RSS 1.0 feed and returns its channel metadata and a normalised list of items -- id, title, link, summary, content, author, dates and categories -- with every date in ISO 8601 UTC. (family feeds, category Data, $0.002, timeout 8000ms) - [sitemap-parse](https://grist.tools/docs/sitemap-parse): Parses a sitemap, a sitemap index or a bare origin into a flat, bounded list of URLs with lastmod, changefreq and priority. (family feeds, category Data, $0.002, timeout 14000ms) - [ssl-cert-info](https://grist.tools/docs/ssl-cert-info): Fetches the TLS certificate a host presents: issuer, subject, SAN list, validity window, days to expiry and the full chain. (family domain, category Verification, $0.002, timeout 10000ms) - [structured-data-extract](https://grist.tools/docs/structured-data-extract): Fetches a web page and returns its embedded machine-readable data -- JSON-LD, OpenGraph, microdata and meta tags -- plus a normalised merge across all four. (family fetch, category Data, $0.002, timeout 8000ms) - [url-to-markdown](https://grist.tools/docs/url-to-markdown): Fetches a web page and returns the article as clean markdown, with its title, byline and final URL. (family fetch, category Data, $0.002, timeout 12000ms) - [url-unshorten](https://grist.tools/docs/url-unshorten): Follows a shortened or tracking URL to its real destination and returns every hop it went through. (family fetch, category Data, $0.002, timeout 10000ms) - [wellknown-fetch](https://grist.tools/docs/wellknown-fetch): Fetches and parses a domain's well-known files -- security.txt (RFC 9116), ads.txt and humans.txt -- returning typed fields, seller records and a cross-file summary in one call. (family feeds, category Data, $0.002, timeout 12000ms) - [whois](https://grist.tools/docs/whois): Registration record for a domain over whois: registrar, creation/update/expiry dates, status codes and nameservers, with the raw response. (family domain, category Verification, $0.002, timeout 12000ms) ## Documents Requires a heavy dependency. - [csv-to-json](https://grist.tools/docs/csv-to-json): Parses a CSV/TSV document into JSON rows, keyed by a header row or as arrays; the delimiter is auto-detected. (family documents, category Content, $0.005, timeout 30000ms) - [docx-to-markdown](https://grist.tools/docs/docx-to-markdown): Converts a Word .docx to Markdown, surfacing anything that did not translate as warnings. (family documents, category Content, $0.005, timeout 40000ms) - [epub-to-text](https://grist.tools/docs/epub-to-text): Extracts an EPUB’s reading-order text and Dublin Core metadata, chapter by chapter. (family documents, category Content, $0.005, timeout 45000ms) - [html-to-pdf](https://grist.tools/docs/html-to-pdf): Renders a web page or an inline HTML string to a PDF, returned base64-encoded with its page count. (family documents, category Content, $0.005, timeout 12000ms) - [json-to-csv](https://grist.tools/docs/json-to-csv): Renders JSON objects as raw CSV with no spreadsheet formula protection; columns are inferred or given, nested values are JSON-encoded. (family documents, category Content, $0.005, timeout 30000ms) - [markdown-to-pdf](https://grist.tools/docs/markdown-to-pdf): Renders a Markdown document to a PDF, returned base64-encoded with its page count. (family documents, category Content, $0.005, timeout 12000ms) - [ocr-image-to-text](https://grist.tools/docs/ocr-image-to-text): Reads the text out of an image (scan, screenshot, photo) with Tesseract, returned with a mean confidence. (family documents, category Content, $0.005, timeout 45000ms) - [pdf-merge](https://grist.tools/docs/pdf-merge): Concatenates 2–8 source PDFs, in order, into one PDF returned base64-encoded. Maximum output PDF size: 25 MiB before base64 encoding. (family documents, category Content, $0.005, timeout 45000ms) - [pdf-metadata](https://grist.tools/docs/pdf-metadata): Reads a PDF's page count, document-info fields, version and encryption flag without rendering it. (family documents, category Content, $0.005, timeout 25000ms) - [pdf-split](https://grist.tools/docs/pdf-split): Extracts a 1-indexed page selection (e.g. "1,3-4") from a PDF into one new PDF, returned base64-encoded. Maximum output PDF size: 25 MiB before base64 encoding. (family documents, category Content, $0.005, timeout 30000ms) - [pdf-to-markdown](https://grist.tools/docs/pdf-to-markdown): Converts a PDF to Markdown, inferring headings from font size (best-effort, not layout-perfect; no OCR). (family documents, category Content, $0.005, timeout 40000ms) - [pdf-to-text](https://grist.tools/docs/pdf-to-text): Extracts the text layer of a PDF, page by page, in reading order (no OCR). (family documents, category Content, $0.005, timeout 40000ms) - [pptx-to-text](https://grist.tools/docs/pptx-to-text): Extracts the slide text of a PowerPoint .pptx, slide by slide, in order (body text only, up to 1,000 slides). (family documents, category Content, $0.005, timeout 40000ms) - [xlsx-to-json](https://grist.tools/docs/xlsx-to-json): Reads an Excel .xlsx into JSON rows, keyed by a header row or as arrays; dates become ISO strings. Archives are limited to 64 worksheets. (family documents, category Content, $0.005, timeout 40000ms) ## Media Requires a heavy dependency. - [archive-extract-file](https://grist.tools/docs/archive-extract-file): Extracts one named entry from a remote zip, tar or tar.gz and returns its bytes (base64) with a sha256. (family archives, category Compute, $0.003, timeout 90000ms) - [archive-inspect](https://grist.tools/docs/archive-inspect): Lists the entries of a remote zip, tar or tar.gz (paths, sizes, compression and CRC) without extracting any of them. (family archives, category Compute, $0.003, timeout 60000ms) - [audio-convert](https://grist.tools/docs/audio-convert): Transcodes an audio file between WAV, MP3, FLAC, AAC and Opus, with an optional bit rate and sample rate. (family av, category Compute, $0.003, timeout 94000ms) - [audio-extract](https://grist.tools/docs/audio-extract): Extracts the audio track from a video (or any container) and returns it in a chosen audio format. (family av, category Compute, $0.003, timeout 94000ms) - [color-palette-extract](https://grist.tools/docs/color-palette-extract): Extracts an image's dominant colours as a small palette (hex, RGB and coverage fraction). (family images, category Compute, $0.003, timeout 60000ms) - [favicon-extract](https://grist.tools/docs/favicon-extract): Discovers a page's favicons and returns the best one decoded to a normalised PNG with its size. (family images, category Compute, $0.003, timeout 45000ms) - [file-type-detect](https://grist.tools/docs/file-type-detect): Detects a remote file's true type from its magic bytes, returning the canonical extension and media type. (family archives, category Compute, $0.003, timeout 30000ms) - [image-compress](https://grist.tools/docs/image-compress): Re-encodes an image in its own format at a lower quality to shrink the file, keeping its dimensions. (family images, category Compute, $0.003, timeout 60000ms) - [image-convert](https://grist.tools/docs/image-convert): Transcodes an image to PNG, JPEG or WebP at a chosen quality, returned base64-encoded. (family images, category Compute, $0.003, timeout 60000ms) - [image-metadata](https://grist.tools/docs/image-metadata): Reads an image's EXIF/ICC/IPTC/XMP metadata and can return a copy with all metadata stripped. (family images, category Compute, $0.003, timeout 30000ms) - [image-probe](https://grist.tools/docs/image-probe): Reports an image's format and pixel dimensions from its header, without decoding the pixels. (family images, category Compute, $0.003, timeout 20000ms) - [image-resize](https://grist.tools/docs/image-resize): Resizes an image to a target width/height under a chosen fit, returned base64-encoded. (family images, category Compute, $0.003, timeout 60000ms) - [media-probe](https://grist.tools/docs/media-probe): Reads a media file's container, duration, bit rate and per-stream codec/resolution without decoding it. (family av, category Compute, $0.003, timeout 30000ms) - [remote-file-hash](https://grist.tools/docs/remote-file-hash): Computes the sha256, sha1 or md5 digest of a remote file, buffered in memory under a size cap, for checksum verification. (family archives, category Compute, $0.003, timeout 60000ms) - [subtitle-convert](https://grist.tools/docs/subtitle-convert): Converts a subtitle track between SubRip (.srt) and WebVTT (.vtt), normalising the cues. (family av, category Compute, $0.003, timeout 15000ms) - [subtitle-extract](https://grist.tools/docs/subtitle-extract): Extracts a text subtitle track from a media container (MKV, MP4, WebM) as SubRip or WebVTT. (family av, category Compute, $0.003, timeout 60000ms) - [svg-to-png](https://grist.tools/docs/svg-to-png): Rasterises an SVG to a PNG at a chosen resolution, returned base64-encoded. (family images, category Compute, $0.003, timeout 60000ms) - [video-thumbnail](https://grist.tools/docs/video-thumbnail): Grabs a single frame from a video at a chosen timestamp as a PNG or JPEG, optionally scaled to a width. (family av, category Compute, $0.003, timeout 60000ms) - [waveform-data](https://grist.tools/docs/waveform-data): Reduces an audio file to a fixed number of normalised waveform peaks for drawing, without shipping samples. (family av, category Compute, $0.003, timeout 90000ms) ## Machine routes - [openapi.json](https://grist.tools/openapi.json): full specification with the x402 pricing extension - [x402 manifest](https://grist.tools/.well-known/x402): discovery manifest - [index.json](https://grist.tools/index.json): machine-readable catalogue - [llms-full.txt](https://grist.tools/llms-full.txt): this file with every schema inlined