# PennyOCR > OCR API for developers and agents: POST a document (PDF/PNG/JPEG/WebP/TIFF), > get its full text back as markdown (tables preserved) or plain text. > $0.75 per 1,000 pages, first 100 pages free. Zero data retention by default. ## MCP server (recommended for agents) Add to mcpServers: {"pennyocr": {"url": "https://mcp.pennyocr.com", "headers": {"Authorization": "Bearer pk_live_..."}}} Tools: read_document {url, pages?, output?, max_pages?, max_cost_usd?} -> {content, pages, cost_usd, citations[]} · estimate_cost {url, pages?} (free). Clients without header support: https://mcp.pennyocr.com/?key=pk_live_... ## API (base: https://api.pennyocr.com) - POST /v1/ocr — multipart form, field `file`; query `?format=markdown|text`; header `Authorization: Bearer pk_live_...`. Response JSON: {id, pages, text, page_results[], cost_usd, model}. Errors: 401 bad key, 402 out of credits, 413 too large (50MB/500 pages), 422 unreadable. - POST /v1/chat/completions — OpenAI Chat Completions compatible. Send image_url content parts (data: or https URLs); model "pennyocr-markdown" or "pennyocr-text". - GET /v1/models — OpenAI-style model list. - POST /v1/ocr/url — JSON {url, format?, pages?, max_pages?, max_cost_usd?}; fetches the document server-side. 413 (with exact numbers) if a cap would be exceeded — decide, then retry. - POST /v1/estimate — JSON {url, pages?} -> {total_pages, selected_pages, cost_usd}. Free. - GET /v1/balance — (Authorization: Bearer pk_live_...) your key's budget: {credit_pages, credit_value_usd, free_pages_available_now, price_per_1k_usd}. Free. Check this before spending; the first 100 pages on an account are free. - POST /v1/billing/checkout — (Authorization: Bearer pk_live_...) JSON {pack: "10k"|"100k"|"1m"} -> {url} to buy prepaid credits with just the API key (no session token). A human finishes payment in the browser. - GET /health — status, no auth. - Machine-readable spec: https://api.pennyocr.com/openapi.yaml (and /openapi.json) ## Signup for agents (no browser needed) 1. POST https://api.pennyocr.com/auth/request-code {"email": "you@example.com"} 2. Read the 6-digit code from that inbox, then POST https://api.pennyocr.com/auth/verify {"email": "...", "code": "123456"} -> {"session_token": "sk_session_..."} 3. POST https://api.pennyocr.com/dashboard/keys (Authorization: Bearer ) -> {"api_key": "pk_live_..."} (shown once) 4. Your first 100 pages are free. To buy prepaid credits: POST https://api.pennyocr.com/dashboard/billing/checkout {"pack": "10k" | "100k" | "1m"} (Authorization: Bearer ) -> {"url": "https://checkout.stripe.com/..."} (complete payment there; a human card holder must finish Stripe checkout) Or, once you hold the API key: POST /v1/billing/checkout {"pack": "..."}. 5. Balance (with the API key): GET /v1/balance. Session usage: GET /dashboard/usage · daily series: GET /dashboard/usage/daily ## Pricing - /pricing.txt: plain-text pricing summary - https://pennyocr.com/ocr-api-pricing/: pricing comparison page ## Docs - https://pennyocr.com/docs/: full API reference - https://pennyocr.com/blog/receipt-ocr-benchmark/: measured accuracy benchmark ## Contact - hello@pennyocr.com (a human replies fast) ## Chrome extension PennyOCR Snip — snip any region of a page (or right-click an image) and get the text. Install: https://chromewebstore.google.com/detail/pennyocr-snip/mpbmgjggnjmembmagibkgeldehgcipgn Source: https://github.com/imiraoui/pennyocr-snip 3 free snips/month with no account; email sign-in raises it to 30/month.