{"openapi":"3.1.0","info":{"title":"html2pptx.app Export API","version":"1.0.0","description":"Convert HTML/CSS to fully editable PowerPoint files. Supports commercial plans with rate limiting, usage quotas, and concurrent job control.","contact":{"url":"https://html2pptx.app"}},"servers":[{"url":"https://html2pptx.app","description":"Production"}],"security":[{"bearerAuth":[]}],"paths":{"/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 idempotency key. Repeating a request with the same key within 24 hours returns the original response."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJobRequest"}}}},"responses":{"200":{"description":"Job created (or completed when waitForCompletion was handled upstream)","headers":{"x-request-id":{"description":"Unique request trace identifier","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportJob"}}}}}}},"/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","headers":{"x-request-id":{"description":"Unique request trace identifier","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportJob"}}}}}}},"/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/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 idempotency key. Repeating a request with the same key within 24 hours returns the original response."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJobRequest"}}}},"responses":{"200":{"description":"Job created (or completed when waitForCompletion was handled upstream)","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"}}}},"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"}}}},"429":{"description":"Rate limit exceeded","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"}}}}}}},"/api/user-templates":{"post":{"operationId":"publishUserTemplate","summary":"Publish a template draft to the creator marketplace","description":"Upload a PPTX and create a draft template that other creators + AI agents can reuse. Slide images are auto-rendered from the PPTX; the creator receives `draftUrl` to pick a cover + metadata and `viewUrl` for the final public page. Any later use of the template (web view / MCP fetch / API+CLI export referencing templateId) earns the author rev-share by point-weighted share of the monthly creator pool.\n\n**Auth**: WorkOS access token (JWT bearer) or browser session. Environment API keys are rejected with 403 because they aren't tied to a creator identity.","tags":["Creator Marketplace"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishTemplateRequest"}},"multipart/form-data":{"schema":{"type":"object","properties":{"pptx":{"type":"string","format":"binary","description":"PowerPoint file (required)"},"html":{"type":"string","format":"binary","description":"HTML source (optional)"},"cover":{"type":"string","format":"binary","description":"Custom cover image (optional)"},"title":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"tags":{"type":"string","description":"JSON-encoded array of strings"},"prompt":{"type":"string"},"premiumOnly":{"type":"string","enum":["true","false"]},"slides":{"type":"string"}},"required":["pptx","title"]}}}},"parameters":[{"name":"async","in":"query","required":false,"schema":{"type":"string","enum":["1"]},"description":"When set to \"1\", returns as soon as the draft is created and slide rendering runs in the background. The response carries `renderStatus: \"pending\"`."}],"responses":{"200":{"description":"Draft created (and, in sync mode, slides rendered).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishTemplateResponse"}}}},"400":{"description":"Validation failure — banned term in text/tag, prompt-injection hit, missing fields, or unsupported content-type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"401":{"description":"Authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"403":{"description":"Authenticated, but the token is not identity-bound (e.g. environment API key). Sign in or use a workspace OAuth key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"413":{"description":"Payload too large — PPTX > 40MB, HTML > 5MB, or cover > 4MB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"get":{"operationId":"listMyTemplates","summary":"List the caller's own templates","tags":["Creator Marketplace"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Array of the caller's templates across all statuses.","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/UserTemplate"}}}}}}},"401":{"description":"Authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/api/user-templates/{id}/publish":{"post":{"operationId":"publishDraftTemplate","summary":"Publish a draft template (make it public)","description":"Transition a draft (or rejected) template to status=published. Requires the draft's PPTX to have rendered successfully.","tags":["Creator Marketplace"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template is now published.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"401":{"description":"Authentication required."},"403":{"description":"Not the creator."},"404":{"description":"Draft not found."}}},"delete":{"operationId":"unpublishTemplate","summary":"Move a published template back to draft","tags":["Creator Marketplace"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template status reset to draft."}}}},"/api/user-templates/{id}/metadata":{"post":{"operationId":"updateTemplateMetadata","summary":"Edit a draft template's metadata","description":"Update title / description / category / tags / prompt / coverSlideIndex / premiumOnly without re-uploading the PPTX.","tags":["Creator Marketplace"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"prompt":{"type":"string"},"premiumOnly":{"type":"boolean"},"coverSlideIndex":{"type":"integer","minimum":0}}}}}},"responses":{"200":{"description":"Metadata updated."},"400":{"description":"Validation failure."},"401":{"description":"Authentication required."},"403":{"description":"Not the creator."}}}},"/api/templates/attribute":{"post":{"operationId":"attributeTemplateUsage","summary":"Attribute template usage for earnings","description":"Credit a template for a generation you just did via REST API, CLI, or any other channel. Safe to call opportunistically — deduping, rate-limiting, and self-exclusion are all enforced server-side. Returns HTTP 200 even when the event is rejected (counted: false + reason).","tags":["Creator Marketplace"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["templateId"],"properties":{"templateId":{"type":"string","description":"Catalog id for built-ins, or slug for user-submitted templates."},"templateSource":{"type":"string","enum":["catalog","user"],"description":"Defaults to catalog."},"eventType":{"type":"string","enum":["view","download","mcp","api","cli"],"description":"Defaults to inferred type: \"cli\" when the UA matches html2pptx-cli, \"api\" otherwise."}}}}}},"responses":{"200":{"description":"Event recorded (see `counted` + `reason` in the response body).","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"counted":{"type":"boolean"},"pointValue":{"type":"number"},"reason":{"type":"string","enum":["self","dedupe","rate_limit","unknown_template","unpublished"]}}}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key passed as a Bearer token in the Authorization header."}},"schemas":{"PublishTemplateRequest":{"type":"object","required":["pptxBase64","title"],"properties":{"pptxBase64":{"type":"string","description":"The PowerPoint file, base64-encoded. Max 40 MB decoded."},"htmlBase64":{"type":"string","description":"Optional HTML source, base64-encoded. Max 5 MB decoded."},"coverBase64":{"type":"string","description":"Optional custom cover image, base64-encoded. Max 4 MB decoded."},"coverContentType":{"type":"string","description":"MIME type for coverBase64 (e.g. \"image/png\")."},"title":{"type":"string","minLength":2,"maxLength":120},"description":{"type":"string","maxLength":400},"category":{"type":"string","description":"ビジネス / デザイン / テクノロジー / その他 or a custom label."},"tags":{"type":"array","items":{"type":"string"},"maxItems":20},"prompt":{"type":"string","maxLength":8000,"description":"DESIGN.md — the prompt used to generate the deck. Must not contain instructions aimed at other AI agents (prompt-injection is blocked)."},"premiumOnly":{"type":"boolean"},"slides":{"type":"integer","minimum":1,"description":"Declared slide count (auto-corrected after the render finishes)."}}},"PublishTemplateResponse":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"string","description":"Convex id of the draft row."},"slug":{"type":"string","description":"URL-safe public slug."},"renderStatus":{"type":"string","enum":["ready","pending","failed"]},"slideImageCount":{"type":"integer"},"viewUrl":{"type":"string","format":"uri","description":"Public template page (available after publish)."},"draftUrl":{"type":"string","format":"uri","description":"Dashboard link where the creator can pick a cover + publish."},"previewApi":{"type":"string","description":"Internal manifest endpoint for slide thumbnails."},"error":{"type":"string","description":"Present only when renderStatus === \"failed\"."}}},"UserTemplate":{"type":"object","properties":{"_id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"prompt":{"type":"string"},"status":{"type":"string","enum":["draft","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","required":["html"],"properties":{"html":{"type":"string","minLength":1,"description":"Slide-oriented HTML markup. Each slide should be a <section class=\"slide\"> element with explicit pixel dimensions."},"css":{"type":"string","description":"Optional CSS applied alongside the HTML."},"fileName":{"type":"string","description":"Optional output file name. Defaults to export.pptx."},"autoEmbedFonts":{"type":"boolean","description":"Attempt to embed detected fonts into the PPTX."},"slideCount":{"type":"integer","minimum":1,"description":"Optional explicit slide count. If omitted, the API estimates it from .slide roots."},"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."},"responseFormat":{"type":"string","enum":["url","base64","both"],"default":"url","description":"Controls how the completed PPTX is delivered. \"url\" returns a presigned download URL, \"base64\" returns the file inline, \"both\" returns both."},"callbackUrl":{"type":"string","format":"uri","description":"Optional HTTPS URL to receive a webhook POST when the job completes or fails. The payload is signed with an HMAC-SHA256 in the x-webhook-signature header."}}},"ExportJob":{"type":"object","properties":{"jobId":{"type":"string","description":"Unique job identifier."},"status":{"type":"string","enum":["pending","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."}}},"PlanCatalog":{"type":"object","properties":{"recommendedPlanId":{"type":"string","description":"The recommended plan identifier."},"plans":{"type":"array","items":{"$ref":"#/components/schemas/Plan"}},"note":{"type":"string"}}},"Plan":{"type":"object","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","properties":{"plan":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"limits":{"type":"object","properties":{"requestsPerMinute":{"type":"integer"},"dailyRequestLimit":{"type":"integer"},"monthlyRequestLimit":{"type":"integer"},"maxSlidesPerJob":{"type":"integer"},"concurrentJobs":{"type":"integer"},"maxPayloadBytes":{"type":"integer"}}},"usage":{"type":"object","properties":{"dailyUsed":{"type":"integer","nullable":true},"dailyRemaining":{"type":"integer","nullable":true},"dailyLimitAvailable":{"type":"boolean"},"dayStartsAt":{"type":"string","format":"date-time"},"dayResetsAt":{"type":"string","format":"date-time"},"monthlyUsed":{"type":"integer","nullable":true},"monthlyRemaining":{"type":"integer","nullable":true},"monthlyLimitAvailable":{"type":"boolean"},"monthStartsAt":{"type":"string","format":"date-time"},"monthResetsAt":{"type":"string","format":"date-time"},"activeJobs":{"type":"integer","nullable":true},"monthlyFairUseState":{"type":"string","enum":["normal","review","upgrade_recommended","unknown"]}}}}},"ProblemDetail":{"type":"object","description":"RFC 9457 Problem Details error response with backwards-compatible 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","message","type","status","title","detail"]}}}}