{"openapi":"3.1.0","info":{"title":"PennyOCR API","description":"Great OCR for pennies. $0.75 per 1,000 pages.","version":"0.1.0"},"paths":{"/auth/request-code":{"post":{"summary":"Request Code","operationId":"request_code_auth_request_code_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestCode"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/verify":{"post":{"summary":"Verify","operationId":"verify_auth_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verify"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/me":{"get":{"summary":"Me","operationId":"me_dashboard_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/dashboard/keys":{"get":{"summary":"List Keys","operationId":"list_keys_dashboard_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"summary":"Create Key","operationId":"create_key_dashboard_keys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewKey"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/dashboard/keys/{key_id}":{"delete":{"summary":"Revoke Key","operationId":"revoke_key_dashboard_keys__key_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/ocr":{"post":{"summary":"Playground Ocr","description":"UI playground: OCR with your session (no API key juggling). Metered\nexactly like the API; the job is stored so it shows on your jobs page.","operationId":"playground_ocr_dashboard_ocr_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"markdown","title":"Format"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_playground_ocr_dashboard_ocr_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/jobs":{"get":{"summary":"List Jobs","operationId":"list_jobs_dashboard_jobs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/dashboard/jobs/{job_id}":{"get":{"summary":"Get Job","operationId":"get_job_dashboard_jobs__job_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Job","operationId":"delete_job_dashboard_jobs__job_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/jobs/{job_id}/rating":{"post":{"summary":"Rate Job","operationId":"rate_job_dashboard_jobs__job_id__rating_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rating"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/settings":{"post":{"summary":"Update Settings","description":"store_results=false is zero-data-retention for API traffic: results are\nreturned to the caller and discarded. Playground jobs are always stored\n(they exist to be viewed) and can be deleted from the jobs page.","operationId":"update_settings_dashboard_settings_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/dashboard/usage":{"get":{"summary":"Usage","operationId":"usage_dashboard_usage_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/dashboard/usage/daily":{"get":{"summary":"Usage Daily","description":"Pages per day, last 30 days (zero-filled client-side).","operationId":"usage_daily_dashboard_usage_daily_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/dashboard/billing/checkout":{"post":{"summary":"Create Checkout","description":"Buy a prepaid credit pack via one-time Stripe Checkout.","operationId":"create_checkout_dashboard_billing_checkout_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/dashboard/billing/packs":{"get":{"summary":"List Packs","operationId":"list_packs_dashboard_billing_packs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/dashboard/billing/auto-reload":{"post":{"summary":"Set Auto Reload","description":"Enable/disable automatic top-ups from the saved card when balance runs low.","operationId":"set_auto_reload_dashboard_billing_auto_reload_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoReloadBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/webhooks/stripe":{"post":{"summary":"Stripe Webhook","operationId":"stripe_webhook_webhooks_stripe_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/chat/completions":{"post":{"summary":"Chat Completions","operationId":"chat_completions_v1_chat_completions_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/models":{"get":{"summary":"List Models","operationId":"list_models_v1_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/estimate":{"post":{"summary":"Estimate","description":"Page count + exact cost for a document URL. Free — nothing is OCR'd.","operationId":"estimate_v1_estimate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EstimateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/ocr/url":{"post":{"summary":"Ocr Url","description":"OCR a document by URL, with page ranges and agent-safe spend guards.","operationId":"ocr_url_v1_ocr_url_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UrlOCRRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OCRResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/v1/ocr":{"post":{"summary":"Ocr","description":"OCR a document (PDF, PNG, JPEG, WebP, TIFF). Billed per page.\n\nformat=markdown (default): structured markdown with tables.\nformat=text: plain text only — significantly faster.","operationId":"ocr_v1_ocr_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"markdown","title":"Format"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_ocr_v1_ocr_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OCRResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AutoReloadBody":{"properties":{"enabled":{"type":"boolean","title":"Enabled"},"pack":{"type":"string","title":"Pack","default":"10k"},"threshold_pages":{"type":"integer","title":"Threshold Pages","default":1000}},"type":"object","required":["enabled"],"title":"AutoReloadBody"},"Body_ocr_v1_ocr_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_ocr_v1_ocr_post"},"Body_playground_ocr_dashboard_ocr_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_playground_ocr_dashboard_ocr_post"},"ChatCompletionRequest":{"properties":{"model":{"type":"string","title":"Model","default":"pennyocr-markdown"},"messages":{"items":{},"type":"array","title":"Messages"},"temperature":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Temperature"},"max_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tokens"},"stream":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Stream"},"top_p":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Top P"},"user":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User"}},"additionalProperties":true,"type":"object","required":["messages"],"title":"ChatCompletionRequest"},"CheckoutBody":{"properties":{"pack":{"type":"string","title":"Pack"},"return_origin":{"type":"string","title":"Return Origin","default":"https://pennyocr.com"}},"type":"object","required":["pack"],"title":"CheckoutBody"},"EstimateRequest":{"properties":{"url":{"type":"string","title":"Url"},"pages":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pages"}},"type":"object","required":["url"],"title":"EstimateRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status","default":"ok"},"engine":{"type":"string","title":"Engine"},"model":{"type":"string","title":"Model"}},"type":"object","required":["engine","model"],"title":"HealthResponse"},"NewKey":{"properties":{"name":{"type":"string","title":"Name","default":"default"}},"type":"object","title":"NewKey"},"OCRResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Request id, e.g. ocr_ab12cd34"},"pages":{"type":"integer","title":"Pages"},"text":{"type":"string","title":"Text","description":"Full extracted text, pages joined by form feeds"},"page_results":{"items":{"$ref":"#/components/schemas/PageResult"},"type":"array","title":"Page Results"},"cost_usd":{"type":"number","title":"Cost Usd"},"model":{"type":"string","title":"Model"}},"type":"object","required":["id","pages","text","page_results","cost_usd","model"],"title":"OCRResponse"},"PageResult":{"properties":{"page":{"type":"integer","title":"Page","description":"1-indexed page number"},"text":{"type":"string","title":"Text"}},"type":"object","required":["page","text"],"title":"PageResult"},"Rating":{"properties":{"rating":{"type":"integer","title":"Rating"}},"type":"object","required":["rating"],"title":"Rating"},"RequestCode":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"RequestCode"},"SettingsBody":{"properties":{"store_results":{"type":"boolean","title":"Store Results"}},"type":"object","required":["store_results"],"title":"SettingsBody"},"UrlOCRRequest":{"properties":{"url":{"type":"string","title":"Url"},"format":{"type":"string","title":"Format","default":"markdown"},"pages":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pages","description":"Page range like '1-20,25'. Default: all."},"max_pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Pages","description":"Refuse (413) if selection exceeds this."},"max_cost_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Cost Usd","description":"Refuse (413) if cost would exceed this."}},"type":"object","required":["url"],"title":"UrlOCRRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"Verify":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"code":{"type":"string","title":"Code"}},"type":"object","required":["email","code"],"title":"Verify"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}