pitch2pdf for AI agents

Convert a presentation to PDF and buy the full searchable deck for $3 with three HTTP requests. The purchase is an HTTP 402 Payment Required handshake — x402 or Stripe's Machine Payments Protocol — so an agent can do the whole thing without a person, an account, or a checkout page.

What an agent can do without a human

  • Convert any supported public link — Pitch, DocSend, Google Slides, Google Drive, Google Docs, Google Sheets, Canva, Prezi, Presentations.AI, Figma Slides, or a direct link to a PDF — with POST /api/convert. No key, no login.
  • Download the free preview: the first 10 slides at full resolution, as a PDF, from the downloadUrl the conversion returns.
  • Read the job with GET /api/jobs/{jobId}/results, which reports the slide count, the preview URL, and agentPaymentsAvailable — whether the server will accept a machine payment right now.
  • Buy the full deck for $3 by paying the 402 challenge on POST /api/jobs/{jobId}/generate-paid, then download it in the size it asked for. The amount is fixed by the server and never read from the request.

The three requests

Everything below is plain HTTP against https://api.pitch2pdf.com. Long values are elided with .

1. Convert. The stream ends with an event: complete that carries the jobId and the free preview:

curl -N -X POST https://api.pitch2pdf.com/api/convert \
  -F url=https://pitch.com/v/your-deck

event: progress
data: {"status":"processing","stage":"capturing","currentSlide":3,"totalSlides":24}

event: complete
data: {"status":"completed","jobId":"job_1788…","numSlides":24,"serviceName":"Pitch","downloadUrl":"https://…/free.pdf"}

2. Ask for the full deck. Unpaid, the server answers 402 with the payment challenge in the headers and a JSON body:

curl -i -X POST https://api.pitch2pdf.com/api/jobs/job_1788…/generate-paid \
  -H 'Content-Type: application/json' -d '{"size":"medium"}'

HTTP/1.1 402 Payment Required
WWW-Authenticate: Payment id="…", realm="api.pitch2pdf.com", method="stripe", intent="charge", request="…", opaque="…"
WWW-Authenticate: Payment id="…", realm="api.pitch2pdf.com", method="tempo", intent="charge", request="…", opaque="…"
PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6Miw…   (base64 x402 v2 requirements: USDC on Base)
Cache-Control: no-store
Content-Type: application/json

{"code":"PAYMENT_REQUIRED","error":"Payment required to generate the paid PDF","jobId":"job_1788…","amountUsd":3,"rails":["spt","x402","tempo"],"docs":"https://www.pitch2pdf.com/agents"}

3. Retry the same request with the credential. The server verifies and settles the payment first, returns a receipt, then streams the PDF build:

curl -N -X POST https://api.pitch2pdf.com/api/jobs/job_1788…/generate-paid \
  -H 'Content-Type: application/json' -d '{"size":"medium"}' \
  -H 'Authorization: Payment <credential>'        # MPP (card via Link, or USDC on Tempo)
  # or, for x402:  -H 'PAYMENT-SIGNATURE: <signed payment payload>'

HTTP/1.1 200 OK
Payment-Receipt: …
PAYMENT-RESPONSE: …                                 # x402 requests only
Content-Type: text/event-stream

event: progress
data: {"stage":"ocr","current":5,"total":24}

event: complete
data: {"downloadUrl":"https://…/medium.pdf","size":"medium"}

Progress stages are starting, ocr, building and uploading; a 30-slide deck takes about a minute and a 120-slide deck five to ten. If the PDF for that size already exists the response is plain JSON instead of a stream: {"downloadUrl":"…","size":"medium","cached":true}. A rejected credential answers 402 again with "code":"PAYMENT_INVALID" and a fresh challenge.

Paying

The 402 advertises every rail the server accepts; the agent pays on whichever one it holds funds for. All of them charge the same $3.

RailWhat the agent needsClient
x402 — USDC on BaseA wallet holding USDC on Base and an x402 client that signs the payment from the PAYMENT-REQUIRED header.@x402/fetch or any x402 client. Clients ship with a per-payment spend limit that may be below $3; raise it for this host.
MPP — card via Shared Payment TokenA Link agent wallet with a saved card. Link issues a one-time token for the challenge; the card details never reach pitch2pdf.npx @stripe/link-cli mpp pay <url> -X POST -d '{"size":"medium"}', or mppx.
MPP — USDC on TempoA Tempo wallet holding USDC.tempo request -X POST --json '{"size":"medium"}' <url>, or mppx.

One line with mppx, which reads the challenge and pays on any rail it is configured for:

npx mppx@latest https://api.pitch2pdf.com/api/jobs/<jobId>/generate-paid -X POST --json '{"size":"medium"}'

Price and what it unlocks

$3 per deck, the same as the one-time unlock a person buys on the results page. The amount is set by the server and pinned into the challenge, so a credential minted for one job at one amount is refused on any other. One payment unlocks:

  • every slide at full resolution — no 10-slide preview limit;
  • an invisible OCR text layer, so the PDF is searchable and copy-pasteable and readable by the next agent in the chain;
  • all three sizes — small, medium, large — built on request and cached, so asking for a second size costs nothing;
  • a free re-capture of the same deck for seven days if the source changes, the same "refresh" a person gets.

Discovery

A machine-readable description of the API — every endpoint, the 402 response, both challenge headers and the price as MPP x-payment-info — is published as OpenAPI 3.1 at https://api.pitch2pdf.com/openapi.json. npx mppx@latest validate https://api.pitch2pdf.com reads it. A prose summary for language models is at /llms.txt (full version: /llms-full.txt).

Errors

StatusBody codeMeaningWhat to do
402PAYMENT_REQUIREDNo payment credential on the request. The challenge is in the headers.Pay the challenge and retry the same request with the credential.
402PAYMENT_INVALIDThe credential was rejected: wrong amount, minted for another job, expired, already spent, or settlement failed. Nothing was charged.Read the fresh challenge from this response and pay again.
403The job is unpaid and machine payments are switched off, so there is no challenge to pay.Check agentPaymentsAvailable on the results endpoint; a person can still unlock the deck at https://www.pitch2pdf.com/results?jobId=….
404No job with that jobId.Use the jobId from the complete event of a conversion.
410The captured slides for this job are gone, so the full PDF cannot be built.Convert the deck again and buy the new job.
503PAYMENT_RAIL_UNAVAILABLEThe rail you paid on could not be reached to verify or settle. Nothing was charged.Retry after a short wait, or pay on another rail from the challenge.
429Rate limit: 60 requests per minute per IP address. The 402 and the paid retry count as two.Wait for the Retry-After header.

Conversion failures (a private deck, an unsupported link, a dead link) come back on the /api/convert stream as event: error with the same code values the CLI documents.

Refunds and support

Agent purchases are refunded under the same policy as purchases made by a person: if the full PDF is unusable or never arrived, email support@pitch2pdf.com with the jobId (and the Payment-Receipt if you have it). Refunds go back to the card or wallet that paid.

Frequently Asked Questions