{"openapi":"3.1.0","info":{"title":"Pdfrender","description":"Programmatic access to **Pdfrender**.\n\n### Authentication\nPass your key in the **`X-API-Key`** request header. Calls without a key are\nserved anonymously at a per-IP tier; a valid key lifts you to your plan's tier.\n\n### Rate limits\nEvery response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and\n`X-RateLimit-Reset` (seconds until the window resets). Over-budget calls return\n`429` with a `Retry-After` header. Check your live budget at `GET /v1/me`.\n\n### Pagination\nList endpoints return a keyset envelope — `{\"items\": [...], \"next_cursor\": \"...\"}`.\nPass `next_cursor` back as the `?cursor=` query param for the next page; it is\n`null` on the last page.\n\n### Errors\nErrors are [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) `problem+json` with a\nstable machine-readable **`code`** (e.g. `rate_limited`, `credits_exhausted`,\n`validation_error`). Branch on `code` — `title`/`detail` text may be reworded.\n\n### Quickstart\n```sh\ncurl -H \"X-API-Key: $API_KEY\" https://api.pdfrender.dev/v1/me\n```\n","version":"1"},"servers":[{"url":"https://api.pdfrender.dev"}],"paths":{"/v1/me":{"get":{"tags":["Account"],"summary":"Your plan, remaining requests, and remaining credits","description":"Check where you stand before a call fails.\n\nReturns the plan this request is being served on, whether it was\nrecognised as yours (send your `X-API-Key`; without one you are served as\nan anonymous visitor on the free allowance), how many requests are left in\nthe current window, how many credits are left in the current billing period\n(on plans priced in credits), and the features your plan includes.\n\nChecking is always free: this call costs no credit and does not count\nagainst your request allowance, so the numbers it reports are the numbers\nyou actually have.","operationId":"get_me","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}}},"security":[{"APIKeyHeader":[]}]}},"/v1/render":{"post":{"tags":["Render"],"summary":"Render an HTML document to a PDF","description":"Returns the PDF bytes as an attachment download.\n\nInline images/fonts/CSS as ``data:`` URIs — external http(s) resources are\nnot fetched (a document that references one is rejected with 400 listing the\nURLs). No JavaScript is executed.","operationId":"render_html_to_pdf","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"security":[{"APIKeyHeader":[]}]}}},"components":{"schemas":{"CreditsInfo":{"properties":{"balance":{"type":"integer","title":"Balance"},"granted":{"type":"integer","title":"Granted"},"period_end":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period End"}},"type":"object","required":["balance","granted"],"title":"CreditsInfo","description":"Your credit balance for the current billing period. `granted` is what\nyour plan included, `balance` what is still unspent, and `period_end` the\ndate (ISO 8601) your allowance refills. Present only on plans that are\npriced in credits."},"MeResponse":{"properties":{"tier":{"type":"string","title":"Tier","description":"The plan this request is served on."},"is_keyed":{"type":"boolean","title":"Is Keyed","description":"Whether the request carried a valid API key. False means you are being served as an anonymous visitor on the free allowance."},"rate_limit":{"$ref":"#/components/schemas/RateLimitInfo"},"credits":{"anyOf":[{"$ref":"#/components/schemas/CreditsInfo"},{"type":"null"}],"description":"Null on plans that are not priced in credits."},"features":{"items":{"type":"string"},"type":"array","title":"Features","description":"The features your plan includes."}},"type":"object","required":["tier","is_keyed","rate_limit","features"],"title":"MeResponse","description":"The `GET /v1/me` payload: who the request is authenticated as, what is\nleft of your request and credit allowances, and which features your plan\nincludes."},"RateLimitInfo":{"properties":{"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"},"remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Remaining"},"reset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Reset"}},"type":"object","title":"RateLimitInfo","description":"How many requests you may still make in the current window — the same\nnumbers as the `X-RateLimit-*` response headers. `limit` is the size of the\nwindow, `remaining` what is left of it, and `reset` how many SECONDS until\nit refills (not a timestamp). All three are `null` in the rare case the\ncounter cannot be read; treat that as \"unknown\", not zero."},"RenderRequest":{"properties":{"html":{"type":"string","title":"Html","description":"The HTML document to render. External http(s) resources are NOT fetched — inline images, fonts and CSS as data: URIs. No JavaScript is executed (WeasyPrint renders HTML + CSS only)."},"filename":{"type":"string","title":"Filename","description":"Filename for the returned PDF's Content-Disposition header.","default":"document.pdf"}},"type":"object","required":["html"],"title":"RenderRequest","description":"A render request: an HTML document and an optional download filename.\n\nSize is NOT capped here (it is enforced in the service as a 413, keyed on\nUTF-8 byte length rather than character count); the schema only guards the\nfilename against header injection."},"Problem":{"description":"The RFC 9457 body that EVERY error response carries.\n\nPublished by :mod:`appkit.openapi` as the schema of every 4xx/5xx in the\nOpenAPI document, replacing FastAPI's stock ``HTTPValidationError`` — which\nno handler in this shell has ever returned, so it documented a shape\ncustomers could not receive. Keep the fields in step with\n:func:`problem_response` below, which builds the body.","properties":{"type":{"default":"about:blank","description":"Problem type URI (RFC 9457).","title":"Type","type":"string"},"title":{"description":"Short human-readable summary of the status.","title":"Title","type":"string"},"status":{"description":"The HTTP status code, repeated in the body.","title":"Status","type":"integer"},"detail":{"description":"What went wrong with THIS request.","title":"Detail","type":"string"},"instance":{"description":"The request path that produced the error.","title":"Instance","type":"string"},"code":{"description":"Stable machine-readable error code — branch on this, never on the prose.","title":"Code","type":"string"},"request_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"description":"Correlation id for this request; quote it when asking for support.","title":"Request Id"},"errors":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"default":null,"description":"Per-field validation failures. Present on 422 only.","title":"Errors"},"upgrade_url":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"description":"Where to add credits or move to a larger plan. Present on 402/403/429.","title":"Upgrade Url"}},"required":["title","status","detail","instance","code"],"title":"Problem","type":"object"}},"securitySchemes":{"APIKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key"}}},"tags":[{"name":"Render"},{"name":"Account","description":"Check your plan, how many requests and credits you have left, and what your plan includes — `GET /v1/me`, which is always free to call."}]}