{"openapi":"3.1.0","info":{"title":"html2pptx.app Export API","version":"1.0.0","description":"Core export/import data-plane contract for converting supported HTML/CSS into PowerPoint files and importing PPTX as HTML. Supported text and simple shapes remain editable; SVGs, icons, and selected complex structures are rasterized. Commercial plans include rate limits, usage quotas, and concurrent job control. WorkOS-bound credential management is a separate control-plane surface and is not described here.","contact":{"url":"https://html2pptx.app"},"license":{"name":"Proprietary","url":"https://html2pptx.app/terms"}},"servers":[{"url":"https://html2pptx.app","description":"Production"}],"security":[{"apiKeyBearerAuth":[]},{"apiKeyHeaderAuth":[]}],"paths":{"/api/import/pptx":{"post":{"operationId":"importPptx","summary":"Convert an existing .pptx into editable HTML slides","description":"Parses PPTX OOXML and returns HTML/SVG slides, resolving theme colors (including clrMap/clrMapOvr), master txStyles, and font families. Synchronous.","tags":["Import"],"requestBody":{"required":true,"description":"Send the .pptx either as multipart/form-data (field \"file\") or as JSON with a base64 payload (handy for JSON-RPC / MCP clients).","content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The .pptx file (max 25 MB)."}}}},"application/json":{"schema":{"type":"object","required":["pptxBase64"],"properties":{"pptxBase64":{"type":"string","description":"Base64-encoded .pptx contents (data URLs accepted)."},"fileName":{"type":"string","description":"Optional original file name. Defaults to presentation.pptx."}}}}}},"responses":{"200":{"description":"Conversion result with html, per-slide HTML, and shared css.","headers":{"x-request-id":{"description":"Unique request trace identifier","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PptxImportResult"}}}},"400":{"description":"Missing/invalid file, unsupported type, or invalid OOXML.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"API key required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"API key not mapped to a plan with API access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"413":{"description":"PPTX exceeds the size limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"500":{"description":"PPTX conversion failed unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/v1/import/pptx":{"post":{"operationId":"importPptxV1","summary":"Convert an existing .pptx into editable HTML slides (v1)","description":"Versioned alias for POST /api/import/pptx. Parses PPTX OOXML and returns HTML/SVG slides, resolving theme colors (incl. clrMap/clrMapOvr), master txStyles and font families. Synchronous.","tags":["Import"],"requestBody":{"required":true,"description":"Send the .pptx either as multipart/form-data (field \"file\") or as JSON with a base64 payload (handy for JSON-RPC / MCP clients).","content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The .pptx file (max 25 MB)."}}}},"application/json":{"schema":{"type":"object","required":["pptxBase64"],"properties":{"pptxBase64":{"type":"string","description":"Base64-encoded .pptx contents (data URLs accepted)."},"fileName":{"type":"string","description":"Optional original file name. Defaults to presentation.pptx."}}}}}},"responses":{"200":{"description":"Conversion result with html, per-slide HTML, and shared css.","headers":{"x-request-id":{"description":"Unique request trace identifier","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PptxImportResult"}}}},"400":{"description":"Missing/invalid file, unsupported type, or invalid OOXML.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"API key required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"API key not mapped to a plan with API access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"413":{"description":"PPTX exceeds the size limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"500":{"description":"PPTX conversion failed unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/v1/export/jobs":{"post":{"operationId":"createExportJobV1","summary":"Create an HTML-to-PPTX export job (v1)","description":"Versioned alias for POST /api/export/jobs. Identical behavior.","tags":["Export"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Optional key for best-effort duplicate suppression, scoped to the authenticated API key, in a process-local cache for up to 24 hours. A restart or different application instance can still create another job, so callers should persist the returned jobId."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJobRequest"}}}},"callbacks":{"jobFinished":{"$ref":"#/components/callbacks/JobFinishedCallback"}},"responses":{"200":{"description":"Queued export job created","headers":{"x-request-id":{"description":"Unique request trace identifier","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportJob"}}}},"400":{"description":"Invalid request (missing HTML, bad JSON)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"API key required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Invalid API key or plan does not include API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"Reusable templateId was not found for this API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"413":{"description":"Payload too large for plan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Slide count exceeds plan limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"429":{"description":"Rate limit, daily limit, monthly limit, or concurrent job limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}},"headers":{"retry-after":{"description":"Seconds to wait before retrying","schema":{"type":"string"}}}},"502":{"description":"Upstream worker unreachable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"Service temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/v1/export/jobs/{jobId}":{"get":{"operationId":"getExportJobV1","summary":"Get export job status (v1)","description":"Versioned alias for GET /api/export/jobs/{jobId}.","tags":["Export"],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"},"description":"The export job identifier."}],"responses":{"200":{"description":"Job status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportJob"}}}},"401":{"description":"API key required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"Job not found, expired, or owned by another API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"502":{"description":"The gateway could not reach the private worker","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"Rate-limit enforcement or the upstream worker is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/v1/export/plans":{"get":{"operationId":"listExportPlansV1","summary":"List available export plans (v1)","description":"Versioned alias for GET /api/export/plans.","tags":["Plans"],"security":[],"responses":{"200":{"description":"Plan catalog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanCatalog"}}}}}}},"/api/v1/export/usage":{"get":{"operationId":"getUsageV1","summary":"Get current usage and quota (v1)","description":"Versioned alias for GET /api/export/usage. Identical behavior.","tags":["Usage"],"responses":{"200":{"description":"Usage snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSnapshot"}}}},"401":{"description":"API key required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"500":{"description":"Usage service failed unexpectedly","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/export/jobs":{"post":{"operationId":"createExportJob","summary":"Create an HTML-to-PPTX export job","description":"Submit HTML (and optional CSS) to convert into a PowerPoint file. The job runs asynchronously; poll the returned jobId for completion.","tags":["Export"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Optional key for best-effort duplicate suppression, scoped to the authenticated API key, in a process-local cache for up to 24 hours. A restart or different application instance can still create another job, so callers should persist the returned jobId."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJobRequest"}}}},"callbacks":{"jobFinished":{"$ref":"#/components/callbacks/JobFinishedCallback"}},"responses":{"200":{"description":"Queued export job created","headers":{"x-request-id":{"description":"Unique request trace identifier","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportJob"}}}},"400":{"description":"Invalid request (missing HTML, bad JSON)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"API key required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Invalid API key or plan does not include API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"Reusable templateId was not found for this API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"413":{"description":"Payload too large for plan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Slide count exceeds plan limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"429":{"description":"Rate limit, daily limit, monthly limit, or concurrent job limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}},"headers":{"retry-after":{"description":"Seconds to wait before retrying","schema":{"type":"string"}}}},"502":{"description":"Upstream worker unreachable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"Service temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/export/jobs/{jobId}":{"get":{"operationId":"getExportJob","summary":"Get export job status","description":"Fetch the current status of a previously created export job.","tags":["Export"],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"},"description":"The export job identifier returned by POST /api/export/jobs."}],"responses":{"200":{"description":"Job status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportJob"}}}},"401":{"description":"API key required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"Job not found, expired, or owned by another API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"502":{"description":"The gateway could not reach the private worker","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"Rate-limit enforcement or the upstream worker is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/export/plans":{"get":{"operationId":"listExportPlans","summary":"List available export plans","description":"Fetch the public commercial plan catalog, including recommended tier.","tags":["Plans"],"security":[],"responses":{"200":{"description":"Plan catalog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanCatalog"}}}}}}},"/api/export/usage":{"get":{"operationId":"getUsage","summary":"Get current usage and quota","description":"Fetch daily/monthly usage, fair-use state, and plan limits for the authenticated API key.","tags":["Usage"],"responses":{"200":{"description":"Usage snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSnapshot"}}}},"401":{"description":"API key required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"500":{"description":"Usage service failed unexpectedly","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/export/templates":{"post":{"operationId":"registerExportTemplate","summary":"Register a reusable export template","description":"Stores slide-oriented HTML/CSS for the authenticated API key and returns a `tpl_` identifier. The identifier is owner-scoped and can replace inline html in POST /api/export/jobs.","tags":["Export Templates"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterExportTemplateRequest"}}}},"responses":{"200":{"description":"Reusable template registered","headers":{"x-request-id":{"description":"Unique request trace identifier","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterExportTemplateResult"}}}},"400":{"description":"Invalid JSON or missing html","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Commercial API key required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Invalid API key or plan does not include API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"413":{"description":"Request or reusable template exceeds the configured limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"502":{"description":"Template storage request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"Reusable template storage is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/v1/export/templates":{"post":{"operationId":"registerExportTemplateV1","summary":"Register a reusable export template (v1)","description":"Versioned alias for POST /api/export/templates. Identical behavior.","tags":["Export Templates"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterExportTemplateRequest"}}}},"responses":{"200":{"description":"Reusable template registered","headers":{"x-request-id":{"description":"Unique request trace identifier","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterExportTemplateResult"}}}},"400":{"description":"Invalid JSON or missing html","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Commercial API key required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Invalid API key or plan does not include API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"413":{"description":"Request or reusable template exceeds the configured limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"502":{"description":"Template storage request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"Reusable template storage is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/templates":{"get":{"operationId":"listCatalogTemplates","summary":"List public catalog templates","description":"Returns the public built-in template catalog. Anonymous callers receive `hasPrompt` but not prompt text. An eligible commercial API key, WorkOS browser session, or WorkOS bearer token receives prompt text for a single-template request and may request it for a list with `include=prompt`. `include=html` is supported for a single template selected with `id`.","tags":["Templates"],"security":[{},{"apiKeyBearerAuth":[]},{"apiKeyHeaderAuth":[]},{"workosBearerAuth":[]},{"workosSessionAuth":[]}],"parameters":[{"name":"category","in":"query","required":false,"schema":{"type":"string"},"description":"Filter the catalog by its canonical category value."},{"name":"id","in":"query","required":false,"schema":{"type":"string"},"description":"Return one template object instead of the `{ templates: [...] }` list envelope."},{"name":"include","in":"query","required":false,"schema":{"type":"array","items":{"type":"string","enum":["prompt","html"]}},"style":"form","explode":false,"description":"Comma-separated optional fields. Prompt text requires an accepted authenticated caller; HTML is only inlined for a single-template request."},{"name":"locale","in":"query","required":false,"schema":{"type":"string"},"description":"Preferred catalog locale. When omitted, the request cookie and Accept-Language header are used."}],"responses":{"200":{"description":"A single catalog template or the catalog list envelope.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CatalogTemplate"},{"$ref":"#/components/schemas/CatalogTemplateList"}]}}}},"404":{"description":"The requested template id was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/user-templates":{"post":{"operationId":"publishUserTemplate","summary":"Disabled REST draft-creation endpoint","deprecated":true,"description":"This REST endpoint no longer creates creator-owned drafts. The supported public HTML draft workflow uses `html2pptx_validate_template_html`, fixes every error, then calls `html2pptx_publish_template` from an authenticated remote MCP client with a WorkOS-bound user token. CLI, local MCP, generic REST API, and PPTX source files are not supported draft-creation contracts; legacy or hidden web surfaces are outside this public workflow. The dashboard can turn a reviewed draft into an unlisted share. New public-gallery publishing is currently disabled.","tags":["Creator Marketplace"],"security":[],"responses":{"403":{"description":"Always returned. REST template draft creation is disabled and no request payload is processed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"get":{"operationId":"listMyTemplates","summary":"List the caller's own templates","description":"Requires a WorkOS browser session whose access token is accepted by the configured Convex AuthKit provider. API keys and generic bearer tokens are not accepted by this endpoint.","tags":["Creator Marketplace"],"security":[{"workosSessionAuth":[]}],"responses":{"200":{"description":"Array of the caller's templates across all statuses.","content":{"application/json":{"schema":{"type":"object","required":["templates"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/UserTemplate"}}}}}}},"401":{"description":"Authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"A bearer or API-key credential was supplied, but this endpoint requires a WorkOS browser session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/user-templates/{id}/publish":{"post":{"operationId":"publishDraftTemplate","summary":"Share a draft template as unlisted","description":"Shares an owned HTML draft with an unlisted link after security checks. Public gallery publishing is currently disabled and a `published` request returns 403.","tags":["Creator Marketplace"],"security":[{"workosSessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["visibility"],"properties":{"visibility":{"type":"string","enum":["unlisted"],"description":"Only unlisted sharing is currently available. `published` is rejected."}}}}}},"responses":{"200":{"description":"Template is now shared as unlisted.","content":{"application/json":{"schema":{"type":"object","required":["ok","visibility"],"properties":{"ok":{"type":"boolean"},"visibility":{"type":"string","enum":["unlisted"]}}}}}},"400":{"description":"HTML security validation rejected the source.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Public gallery publishing is disabled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"404":{"description":"Draft not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"429":{"description":"Template visibility change rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"500":{"description":"Template validation, storage, or state update failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"delete":{"operationId":"unpublishTemplate","summary":"Move a published template back to draft","tags":["Creator Marketplace"],"security":[{"workosSessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template status reset to draft.","content":{"application/json":{"schema":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean","const":true}}}}}},"401":{"description":"Authentication required."},"429":{"description":"Too many template visibility changes."},"500":{"description":"Template storage failed unexpectedly."}}}},"/api/user-templates/{id}/metadata":{"post":{"operationId":"updateTemplateMetadata","summary":"Edit a draft template's metadata","description":"Update title / description / category / tags / prompt / coverSlideIndex / premiumOnly / allowSourceView without re-uploading the source file.","tags":["Creator Marketplace"],"security":[{"workosSessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"title":{"type":"string","minLength":2,"maxLength":120},"description":{"type":"string","maxLength":400},"category":{"type":"string","maxLength":40},"tags":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":40}},"prompt":{"type":"string","maxLength":8000,"description":"DESIGN.md content. Instruction-like prompt injection is rejected."},"premiumOnly":{"type":"boolean"},"allowSourceView":{"type":"boolean","description":"Expose the stored HTML source as text/plain to non-owners when true. Defaults to private."},"coverSlideIndex":{"type":"integer","minimum":0}}}}}},"responses":{"200":{"description":"Metadata updated."},"400":{"description":"Validation failure."},"401":{"description":"Authentication required."},"404":{"description":"Template not found or not owned by the caller."},"500":{"description":"Metadata storage failed unexpectedly."}}}}},"components":{"securitySchemes":{"apiKeyBearerAuth":{"type":"http","scheme":"bearer","description":"Commercial API key passed as `Authorization: Bearer <key>` for export endpoints."},"apiKeyHeaderAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Commercial API key passed in the `x-api-key` header."},"workosBearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"WorkOS access token that establishes the creator identity. A commercial API key is not interchangeable with this credential."},"workosSessionAuth":{"type":"apiKey","in":"cookie","name":"wos-session","description":"WorkOS browser session cookie (default name; deployments may override WORKOS_COOKIE_NAME). Creator dashboard mutations require this session authentication."}},"callbacks":{"JobFinishedCallback":{"{$request.body#/callbackUrl}":{"post":{"operationId":"receiveExportJobNotification","summary":"Receive an export completion or failure hint","description":"Unsigned delivery hint sent by html2pptx.app. Do not trust it as the final result; acknowledge it and fetch the authenticated job status endpoint.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookNotification"}}}},"responses":{"200":{"description":"Notification acknowledged."},"400":{"description":"Notification rejected by the receiver."}}}}}},"schemas":{"RegisterExportTemplateRequest":{"type":"object","required":["html"],"properties":{"name":{"type":"string","description":"Optional template name. Defaults to Untitled template."},"html":{"type":"string","minLength":1,"description":"Slide-oriented HTML to store for later export. The combined HTML/CSS storage limit is enforced server-side."},"css":{"type":"string","description":"Optional stylesheet stored with the reusable template."}}},"RegisterExportTemplateResult":{"type":"object","required":["templateId","updated"],"properties":{"templateId":{"type":"string","pattern":"^tpl_","description":"Owner-scoped identifier accepted by CreateJobRequest.templateId for the same API key."},"updated":{"type":"boolean","description":"Whether an existing record with this server-generated identifier was updated. New public registrations normally return false."}}},"PptxImportResult":{"type":"object","description":"Result of converting a .pptx into HTML slides.","required":["fileName","plan","label","slideCount","slides","html","css","warnings"],"properties":{"fileName":{"type":"string"},"plan":{"type":"string","description":"Commercial plan id used for the request."},"label":{"type":["string","null"]},"slideCount":{"type":"integer"},"slides":{"type":"array","description":"Per-slide objects.","items":{"type":"object","required":["index","source","layout","html"],"properties":{"index":{"type":"integer"},"source":{"type":"string"},"layout":{"type":["string","null"]},"html":{"type":"string"}}}},"html":{"type":"string","description":"Full deck HTML document."},"css":{"type":"string","description":"Shared stylesheet for the slides."},"warnings":{"type":"array","items":{"type":"string"}}}},"CatalogTemplate":{"type":"object","required":["id","title","description","category","categoryLabel","slides","author","htmlUrl","downloadUrl","thumbnailUrl","hasPrompt"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"categoryLabel":{"type":"string"},"slides":{"type":"integer"},"author":{"type":"string"},"htmlUrl":{"type":["string","null"],"format":"uri"},"downloadUrl":{"type":"string","format":"uri","description":"Authenticated PPTX download endpoint for the template."},"thumbnailUrl":{"type":"string","format":"uri"},"hasPrompt":{"type":"boolean"},"prompt":{"type":"string","description":"Present for an authenticated single-template request when available, or for an authenticated list request with `include=prompt`."},"html":{"type":"string","description":"Only present when a single template is selected with `id` and `include=html` is requested."}}},"CatalogTemplateList":{"type":"object","required":["templates"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/CatalogTemplate"}}}},"UserTemplate":{"type":"object","required":["_id","slug","title","slides","status","createdAt","updatedAt"],"properties":{"_id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"slides":{"type":"integer"},"description":{"type":"string"},"category":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"prompt":{"type":"string"},"status":{"type":"string","enum":["draft","unlisted","pending_review","published","rejected","removed"]},"renderStatus":{"type":"string","enum":["pending","rendering","ready","failed"]},"slideImageCount":{"type":"integer"},"coverSlideIndex":{"type":"integer"},"premiumOnly":{"type":"boolean"},"publishedAt":{"type":"integer","description":"Unix ms timestamp."},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"}}},"CreateJobRequest":{"type":"object","description":"Provide either non-empty `html`, or a reusable export `templateId` beginning with `tpl_`. `data` may be merged into either source before sanitization.","anyOf":[{"required":["html"]},{"required":["templateId"],"properties":{"templateId":{"type":"string","pattern":"^tpl_"}}}],"properties":{"html":{"type":"string","minLength":1,"description":"Slide-oriented HTML markup. Required unless `templateId` resolves to a reusable export template owned by this API key. Each slide should be a <section class=\"slide\"> element with explicit pixel dimensions."},"css":{"type":"string","description":"Optional CSS applied alongside the HTML."},"templateId":{"type":"string","pattern":"^tpl_[A-Za-z0-9_-]+$","description":"Reusable export template id returned by POST /api/export/templates for the same API key. Only ids with the `tpl_` prefix are resolved as export templates."},"data":{"type":"object","additionalProperties":true,"description":"Template variables merged into `html`/`css` or the reusable template before sanitization. Arrays and primitive values are not treated as template data."},"fileName":{"type":"string","description":"Optional output file name. Defaults to export.pptx."},"autoEmbedFonts":{"type":"boolean","description":"Compatibility input forwarded to the renderer. The public REST sanitizer removes @font-face rules and the worker blocks external font downloads, so this does not fetch Google Fonts or arbitrary web-font URLs."},"slideCount":{"type":"integer","minimum":1,"deprecated":true,"description":"Accepted for backwards compatibility but ignored by the public gateway. The effective slide count is always recalculated from sanitized HTML elements whose class contains `slide`."},"metadata":{"type":"object","additionalProperties":true,"description":"Optional metadata forwarded to the export worker."},"width":{"type":"number","description":"Optional PPTX slide width in inches."},"height":{"type":"number","description":"Optional PPTX slide height in inches."},"layout":{"type":"string","description":"Optional PPTX layout preset. Examples: LAYOUT_16x9, LAYOUT_16x10, LAYOUT_4x3, LAYOUT_WIDE."},"aspectRatio":{"type":"string","pattern":"^(?:16\\s*[:x×]\\s*9|16\\s*[:x×]\\s*10|4\\s*[:x×]\\s*3)$","description":"Optional aspect ratio. Accepted forms use `:`, `x`, or `×` separators for 16:9, 16:10, or 4:3. Unsupported values are ignored."},"callbackUrl":{"type":"string","format":"uri","pattern":"^https://","description":"Optional HTTPS URL to receive a WebhookNotification when the job completes or fails. The notification is not the full job result and must be treated only as a delivery hint. No customer-verifiable webhook signing contract is currently exposed; fetch the authenticated status endpoint for downloadUrl or fileBase64."}}},"ExportJob":{"type":"object","required":["jobId","status"],"properties":{"jobId":{"type":"string","description":"Unique job identifier."},"status":{"type":"string","enum":["queued","processing","completed","failed"],"description":"Current job status."},"fileName":{"type":"string","description":"Output file name."},"downloadUrl":{"type":"string","format":"uri","description":"Presigned URL to download the completed PPTX file."},"statusUrl":{"type":"string","format":"uri","description":"URL to poll for job status updates."},"message":{"type":"string","description":"Human-readable status message."},"slideCount":{"type":"integer","description":"Effective slide count calculated from the sanitized HTML."},"fileBase64":{"type":"string","description":"May be returned by the worker as a fallback when a download URL cannot be produced. Public REST callers cannot request a response format."},"mimeType":{"type":"string","description":"MIME type of the completed export."}}},"WebhookNotification":{"oneOf":[{"type":"object","required":["ok","status","jobId","fileName"],"properties":{"ok":{"type":"boolean","const":true},"status":{"type":"string","const":"completed"},"jobId":{"type":"string"},"fileName":{"type":"string"},"downloadUrl":{"type":"string","format":"uri","description":"May appear in legacy worker mode. Durable mode callers should retrieve the result from the status endpoint."}}},{"type":"object","required":["ok","status","jobId","message"],"properties":{"ok":{"type":"boolean","const":false},"status":{"type":"string","const":"failed"},"jobId":{"type":"string"},"message":{"type":"string"}}}],"description":"Completion/failure notification sent to callbackUrl. The complete ExportJob result remains available from the status endpoint."},"PlanCatalog":{"type":"object","required":["recommendedPlanId","plans","note"],"properties":{"recommendedPlanId":{"type":"string","description":"The recommended plan identifier."},"plans":{"type":"array","items":{"$ref":"#/components/schemas/Plan"}},"note":{"type":"string"}}},"Plan":{"type":"object","required":["id","name","priceLabel","limits"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"priceLabel":{"type":"string"},"limits":{"type":"object","properties":{"requestsPerMinute":{"type":"integer"},"maxSlidesPerJob":{"type":"integer"},"concurrentJobs":{"type":"integer"},"maxPayloadBytes":{"type":"integer"},"dailyRequestLimit":{"type":"integer"},"monthlyRequestLimit":{"type":"integer"}}}}},"UsageSnapshot":{"type":"object","required":["plan","limits","usage"],"properties":{"plan":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string"},"name":{"type":"string"}}},"limits":{"type":"object","required":["requestsPerMinute","dailyRequestLimit","monthlyRequestLimit","monthlyReviewThreshold","monthlyUpgradePromptThreshold","maxSlidesPerJob","concurrentJobs","maxPayloadBytes"],"properties":{"requestsPerMinute":{"type":"integer"},"dailyRequestLimit":{"type":"integer"},"monthlyRequestLimit":{"type":"integer"},"monthlyReviewThreshold":{"type":"integer"},"monthlyUpgradePromptThreshold":{"type":"integer"},"maxSlidesPerJob":{"type":"integer"},"concurrentJobs":{"type":"integer"},"maxPayloadBytes":{"type":"integer"}}},"usage":{"type":"object","required":["dailyUsed","dailyRemaining","dailyLimitAvailable","dayStartsAt","dayResetsAt","monthlyUsed","monthlyRemaining","monthlyLimitAvailable","monthStartsAt","monthResetsAt","activeJobs","monthlyFairUseState"],"properties":{"dailyUsed":{"type":["integer","null"]},"dailyRemaining":{"type":["integer","null"]},"dailyLimitAvailable":{"type":"boolean"},"dayStartsAt":{"type":"string","format":"date-time"},"dayResetsAt":{"type":"string","format":"date-time"},"monthlyUsed":{"type":["integer","null"]},"monthlyRemaining":{"type":["integer","null"]},"monthlyLimitAvailable":{"type":"boolean"},"monthStartsAt":{"type":"string","format":"date-time"},"monthResetsAt":{"type":"string","format":"date-time"},"activeJobs":{"type":["integer","null"]},"monthlyFairUseState":{"type":"string","enum":["normal","review","upgrade_recommended","unknown"]}}}}},"ProblemDetail":{"type":"object","description":"Error response shared by routes with different maturity levels. `error` is always present. Commercial export errors also include the RFC 9457 fields `type`, `status`, `title`, and `detail`; legacy and creator routes may only include `error`, `message`, and route-specific fields.","properties":{"error":{"type":"string","description":"Machine-readable error code (snake_case)."},"message":{"type":"string","description":"Human-readable error description (legacy field)."},"type":{"type":"string","format":"uri","description":"RFC 9457 problem type URI."},"status":{"type":"integer","description":"HTTP status code."},"title":{"type":"string","description":"Short human-readable title (Title Case of error code)."},"detail":{"type":"string","description":"Detailed human-readable explanation (same as message)."},"instance":{"type":"string","description":"Request path that generated this error (when available)."}},"required":["error"]}}}}