{"openapi":"3.1.0","info":{"title":"pdfbrew API","version":"1.0.0","description":"PDF infrastructure as a service. Render HTML, Markdown, or URLs to pixel-perfect PDFs with a single API call. Supports async rendering, webhooks, content caching, idempotency, custom fonts, and plan-based quotas.","contact":{"name":"pdfbrew support","email":"support@pdfbrew.coffee"}},"servers":[{"url":"https://api.pdfbrew.coffee","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key (`pdfbrew_live_` for production, `pdfbrew_test_` for testing) or dashboard session token (`pdfbrew_sess_`). Create API keys via `POST /v1/keys`."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["invalid_source","invalid_options","invalid_request","render_timeout","render_failed","rate_limited","quota_exceeded","concurrent_limit","unauthorized","not_found","idempotency_conflict","internal_error"]},"message":{"type":"string"}}}}},"RenderOptions":{"type":"object","properties":{"format":{"type":"string","enum":["A4","A3","Letter","Legal"],"default":"A4","description":"Page size."},"margin":{"type":"object","properties":{"top":{"type":"string","example":"20px"},"bottom":{"type":"string","example":"20px"},"left":{"type":"string","example":"20px"},"right":{"type":"string","example":"20px"}}},"landscape":{"type":"boolean","default":false},"scale":{"type":"number","minimum":0.1,"maximum":2,"default":1},"print_background":{"type":"boolean","default":true,"description":"Print background graphics."},"header_template":{"type":"string","description":"HTML template for the page header."},"footer_template":{"type":"string","description":"HTML template for the page footer."},"wait_until":{"type":"string","enum":["load","domcontentloaded","networkidle0","networkidle2"],"default":"networkidle0","description":"When to consider the page loaded."},"wait_for_selector":{"type":"string","description":"CSS selector to wait for before printing."},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Extra HTTP request headers (URL source only)."},"timeout_ms":{"type":"integer","minimum":1000,"maximum":30000,"default":30000,"description":"Render timeout in milliseconds."}}},"RenderOutput":{"type":"object","required":["url","expires_at","sha256","bytes","pages"],"properties":{"url":{"type":"string","format":"uri","description":"Signed download URL (valid for 1 hour). Always fresh when fetched via `GET /v1/renders/{id}`."},"expires_at":{"type":"string","format":"date-time"},"sha256":{"type":"string","description":"SHA-256 hex digest of the normalized PDF bytes."},"bytes":{"type":"integer","description":"File size in bytes."},"pages":{"type":"integer","description":"Number of pages."}}},"Render":{"type":"object","required":["id","status","created_at"],"properties":{"id":{"type":"string","example":"rnd_abc123"},"status":{"type":"string","enum":["queued","rendering","completed","failed"]},"source_type":{"type":"string","enum":["html","url","markdown"]},"cache_hit":{"type":"boolean","description":"Present and `true` when the result was served from the content-addressed cache."},"output":{"oneOf":[{"$ref":"#/components/schemas/RenderOutput"},{"type":"null"}]},"error":{"oneOf":[{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}},{"type":"null"}]},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":"string","format":"date-time","nullable":true}}},"ApiKey":{"type":"object","required":["id","name","environment","renders_today","created_at"],"properties":{"id":{"type":"string","example":"key_abc123"},"name":{"type":"string","example":"Production"},"environment":{"type":"string","enum":["live","test"]},"last_used_at":{"type":"string","format":"date-time","nullable":true},"renders_today":{"type":"integer","description":"Render count in the last 24 hours."},"created_at":{"type":"string","format":"date-time"}}},"CreatedApiKey":{"allOf":[{"$ref":"#/components/schemas/ApiKey"},{"type":"object","required":["key"],"properties":{"key":{"type":"string","example":"pdfbrew_live_abc123","description":"Raw API key value. Shown **only once** at creation. Store it securely."}}}]},"Font":{"type":"object","required":["id","family","filename","format","bytes","created_at"],"properties":{"id":{"type":"string","example":"fnt_abc123"},"family":{"type":"string","example":"Inter","description":"CSS font-family name used in @font-face."},"filename":{"type":"string","example":"Inter-Regular.woff2"},"format":{"type":"string","enum":["woff2","woff","truetype","opentype"]},"bytes":{"type":"integer","description":"File size in bytes."},"created_at":{"type":"string","format":"date-time"}}},"BillingStatus":{"type":"object","required":["plan","subscription_status"],"properties":{"plan":{"type":"string","enum":["free","pro","business"]},"subscription_status":{"type":"string","enum":["active","on_hold","inactive"]},"dodo_subscription_id":{"type":"string","nullable":true}}},"Stats":{"type":"object","properties":{"total":{"type":"integer","description":"All-time render count."},"today":{"type":"integer","description":"Renders in the last 24 hours."},"this_month":{"type":"integer","description":"Renders in the current calendar month."},"by_status":{"type":"object","properties":{"completed":{"type":"integer"},"failed":{"type":"integer"},"queued":{"type":"integer"},"rendering":{"type":"integer"}}},"daily":{"type":"array","description":"Render counts per day for the last 30 days.","items":{"type":"object","properties":{"day":{"type":"string","format":"date"},"count":{"type":"integer"}}}}}}}},"paths":{"/v1/renders":{"get":{"operationId":"listRenders","summary":"List renders","description":"Returns renders for the account, newest first. Supports cursor-based pagination via `before` and `status` filtering.","tags":["Renders"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"before","in":"query","schema":{"type":"string"},"description":"Render ID to paginate before."},{"name":"status","in":"query","schema":{"type":"string","enum":["queued","rendering","completed","failed"]}}],"responses":{"200":{"description":"Paginated list of renders.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Render"}},"has_more":{"type":"boolean"},"next_before":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createRender","summary":"Create a render","description":"Render HTML, Markdown, or a URL to a PDF.\n\n**Source types:**\n- `html` — raw HTML string with optional CSS\n- `markdown` — Markdown string, converted to styled HTML automatically\n- `url` — publicly reachable URL (Chromium fetches and renders it)\n\n**Content cache**: Identical inputs return instantly from cache. Pass `force_render: true` to bypass.\n\n**Idempotency**: Pass `Idempotency-Key` header to safely retry without double-rendering.\n\n**Quotas**: 429 is returned if the monthly render limit or concurrent render cap for your plan is reached.","tags":["Renders"],"parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"},"description":"Unique key (UUID recommended). Repeated requests with the same key and body return the original render without re-rendering."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["source"],"properties":{"source":{"oneOf":[{"type":"object","required":["type","html"],"properties":{"type":{"type":"string","enum":["html"]},"html":{"type":"string","maxLength":10485760,"description":"HTML content to render."},"css":{"type":"string","description":"Additional CSS injected into the page."}}},{"type":"object","required":["type","markdown"],"properties":{"type":{"type":"string","enum":["markdown"]},"markdown":{"type":"string","maxLength":10485760,"description":"Markdown content. Converted to styled HTML before rendering."},"css":{"type":"string","description":"Additional CSS appended to the default Markdown styles."}}},{"type":"object","required":["type","url"],"properties":{"type":{"type":"string","enum":["url"]},"url":{"type":"string","format":"uri","description":"URL to render. Must be publicly reachable. Private/internal IPs are blocked."}}}]},"options":{"$ref":"#/components/schemas/RenderOptions"},"async":{"type":"boolean","default":true,"description":"Return immediately with a queued render (`true`) or wait for completion (`false`, max 30s)."},"force_render":{"type":"boolean","default":false,"description":"Bypass the content-addressed cache and always perform a fresh render."},"webhook_url":{"type":"string","format":"uri","description":"URL to POST on render completion or failure."}}},"examples":{"html_sync":{"summary":"Sync HTML render","value":{"source":{"type":"html","html":"<h1>Invoice #42</h1>"},"async":false,"options":{"format":"A4"}}},"markdown_sync":{"summary":"Sync Markdown render","value":{"source":{"type":"markdown","markdown":"# Invoice #42\n\n| Item | Price |\n|---|---|\n| Widget | $10 |"},"async":false}},"url_async":{"summary":"Async URL render with webhook","value":{"source":{"type":"url","url":"https://example.com"},"async":true,"webhook_url":"https://your-app.com/webhooks/pdf"}},"force_render":{"summary":"Bypass cache","value":{"source":{"type":"html","html":"<h1>Always fresh</h1>"},"force_render":true}}}}}},"responses":{"200":{"description":"Sync render completed or cache hit.","headers":{"X-Cache":{"schema":{"type":"string","enum":["HIT"]},"description":"Present when result is from cache."},"X-RateLimit-Limit-RPM":{"schema":{"type":"integer"}},"X-RateLimit-Remaining-RPM":{"schema":{"type":"integer"}},"X-RateLimit-Limit-Daily":{"schema":{"type":"integer"}},"X-RateLimit-Remaining-Daily":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Render"}}}},"202":{"description":"Async render queued.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["queued"]},"created_at":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency key conflict.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit, monthly quota, or concurrent render cap exceeded. Check `error.code` for `rate_limited`, `quota_exceeded`, or `concurrent_limit`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/renders/{id}":{"get":{"operationId":"getRender","summary":"Get a render","description":"Fetch the current status of a render. For completed renders, always returns a **fresh 1-hour signed download URL** — never a stale link.","tags":["Renders"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"rnd_abc123"}],"responses":{"200":{"description":"Render object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Render"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Render not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/renders/{id}/file":{"get":{"operationId":"downloadRender","summary":"Download a PDF","description":"Stream the rendered PDF. No API key required — access is controlled by the signed URL token embedded in the download URL returned by `GET /v1/renders/{id}`.","tags":["Renders"],"security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"expires","in":"query","required":true,"schema":{"type":"integer"},"description":"Expiry timestamp (ms since epoch)."},{"name":"sig","in":"query","required":true,"schema":{"type":"string"},"description":"HMAC-SHA256 signature."}],"responses":{"200":{"description":"PDF file stream.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Invalid or expired token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Render not found or not yet completed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/fonts":{"get":{"operationId":"listFonts","summary":"List fonts","description":"Returns all uploaded fonts for the account. Fonts are automatically injected as `@font-face` CSS into every render.","tags":["Fonts"],"responses":{"200":{"description":"List of fonts.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Font"}}}}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"uploadFont","summary":"Upload a font","description":"Upload a font file (woff2, woff, ttf, or otf). Once uploaded, the font is automatically injected into all renders via `@font-face`. Max 5 MB per file.\n\nReference the font in your HTML/CSS using the `family` name you provide.","tags":["Fonts"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["family","file"],"properties":{"family":{"type":"string","description":"CSS font-family name. Use this name in your HTML/CSS `font-family` declarations.","example":"Inter"},"file":{"type":"string","format":"binary","description":"Font file. Supported formats: woff2, woff, ttf, otf."}}}}}},"responses":{"201":{"description":"Font uploaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Font"}}}},"400":{"description":"Invalid request or unsupported format.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/fonts/{id}":{"delete":{"operationId":"deleteFont","summary":"Delete a font","description":"Removes the font and its R2 object. Future renders will no longer inject this font.","tags":["Fonts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"fnt_abc123"}],"responses":{"204":{"description":"Font deleted."},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Font not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/keys":{"get":{"operationId":"listKeys","summary":"List API keys","description":"Returns all active (non-revoked) API keys for the account.","tags":["API Keys"],"responses":{"200":{"description":"List of API keys.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createKey","summary":"Create an API key","description":"Create a new API key. The raw key value is returned **only once** — store it immediately.","tags":["API Keys"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"example":"Production"},"environment":{"type":"string","enum":["live","test"],"default":"live"}}}}}},"responses":{"201":{"description":"Key created. The `key` field is only present in this response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedApiKey"}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/keys/{id}":{"delete":{"operationId":"deleteKey","summary":"Revoke an API key","description":"Permanently revokes the key. All subsequent requests using this key will return 401. Irreversible.","tags":["API Keys"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"key_abc123"}],"responses":{"204":{"description":"Key revoked."},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found or already revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks":{"get":{"operationId":"listWebhooks","summary":"List webhook endpoints","tags":["Webhooks"],"responses":{"200":{"description":"List of webhook endpoints.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string","format":"date-time"}}}}}}}}}}},"post":{"operationId":"createWebhook","summary":"Create a webhook endpoint","description":"Register a URL to receive event notifications. A signing secret is returned **only at creation** — use it to verify the `X-Pdfops-Signature` header on incoming requests.","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["render.completed","render.failed"]},"default":["render.completed","render.failed"]}}}}}},"responses":{"201":{"description":"Endpoint created.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"secret":{"type":"string","description":"Signing secret. Shown once — store immediately."},"created_at":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks/{id}":{"delete":{"operationId":"deleteWebhook","summary":"Delete a webhook endpoint","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted."},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/stats":{"get":{"operationId":"getStats","summary":"Get usage stats","description":"Returns render counts broken down by all-time total, today, current month, status, and a 30-day daily chart.","tags":["Account"],"responses":{"200":{"description":"Usage stats.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Stats"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/settings":{"get":{"operationId":"getSettings","summary":"Get account settings","tags":["Account"],"responses":{"200":{"description":"Account settings.","content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"plan":{"type":"string","enum":["free","pro","business"]},"retention_days":{"type":"integer","minimum":1,"maximum":30,"description":"How long PDFs are stored in R2 before deletion."},"created_at":{"type":"string","format":"date-time"}}}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateSettings","summary":"Update account settings","description":"Update the PDF retention period. Affects new renders only — existing PDFs are not immediately deleted.","tags":["Account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["retention_days"],"properties":{"retention_days":{"type":"integer","minimum":1,"maximum":30}}},"example":{"retention_days":14}}}},"responses":{"200":{"description":"Settings updated.","content":{"application/json":{"schema":{"type":"object","properties":{"retention_days":{"type":"integer"}}}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/billing/status":{"get":{"operationId":"getBillingStatus","summary":"Get billing status","description":"Returns the current plan, subscription status, and Dodo Payments subscription ID.","tags":["Billing"],"responses":{"200":{"description":"Billing status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingStatus"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/billing/checkout":{"post":{"operationId":"createCheckout","summary":"Create a checkout session","description":"Creates a Dodo Payments hosted checkout session. Redirect the user to the returned `checkout_url`. On success, Dodo fires a webhook that upgrades the account plan automatically.","tags":["Billing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan"],"properties":{"plan":{"type":"string","enum":["pro","business"]}}},"example":{"plan":"pro"}}}},"responses":{"200":{"description":"Checkout session created.","content":{"application/json":{"schema":{"type":"object","properties":{"checkout_url":{"type":"string","format":"uri"}}}}}},"400":{"description":"Invalid plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/billing/change-plan":{"post":{"operationId":"changePlan","summary":"Change plan","description":"Switch between paid plans (e.g. Business → Pro) without going through checkout again. Uses Dodo Payments `changePlan` API with prorated billing.","tags":["Billing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan"],"properties":{"plan":{"type":"string","enum":["pro","business"]}}}}}},"responses":{"200":{"description":"Plan changed.","content":{"application/json":{"schema":{"type":"object","properties":{"plan":{"type":"string"}}}}}},"400":{"description":"Invalid request or no active subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/billing/cancel":{"post":{"operationId":"cancelSubscription","summary":"Cancel subscription","description":"Cancels the active Dodo Payments subscription immediately and downgrades the account to the Free plan.","tags":["Billing"],"responses":{"200":{"description":"Subscription cancelled.","content":{"application/json":{"schema":{"type":"object","properties":{"cancelled":{"type":"boolean"}}}}}},"400":{"description":"No active subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/magic-link":{"post":{"operationId":"requestMagicLink","summary":"Request a magic link","description":"Send a login link to the given email address. The link expires in 15 minutes and can only be used once. No API key required.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"}}},"example":{"email":"you@example.com"}}}},"responses":{"200":{"description":"Email sent.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"400":{"description":"Invalid email.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Email delivery failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/verify":{"get":{"operationId":"verifyMagicLink","summary":"Verify a magic link","description":"Exchange a magic link token for a dashboard session. Called automatically when the user clicks the login link.","tags":["Auth"],"security":[],"parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"Raw token from the magic link URL."}],"responses":{"200":{"description":"Signed in.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"account":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"plan":{"type":"string"}}}}}}}},"401":{"description":"Invalid, expired, or already-used token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"tags":[{"name":"Renders","description":"Create and retrieve PDF renders (HTML, Markdown, URL)."},{"name":"Fonts","description":"Upload custom fonts that are auto-injected into every render."},{"name":"API Keys","description":"Manage API keys for your account."},{"name":"Webhooks","description":"Manage webhook endpoints for render events."},{"name":"Account","description":"Usage stats and account settings."},{"name":"Billing","description":"Plan management via Dodo Payments."},{"name":"Auth","description":"Magic link authentication."}]}