# html2pptx.app

> html2pptx.app converts your HTML and CSS into fully editable PowerPoint files -- not screenshots. Your text stays editable, layouts are preserved, and CSS properties like Flexbox, Grid, gradients, and shadows are faithfully reproduced. The result is a production-ready presentation file.

## Quick Start

The REST API is asynchronous: create a job, poll status, then decode the returned fileBase64 when the job is completed.

### Step 1: Sign Up
Create an account at <a href="https://html2pptx.app" target="_blank" rel="noopener noreferrer" class="text-blue-600 underline hover:text-blue-800">html2pptx.app</a>. Free Preview lets you validate output quality, and Founder Beta unlocks API keys for real API usage.

### Step 2: Get API Key
Navigate to the Dashboard and click "Create API Key". Copy and store it securely -- it will only be shown once. Your key starts with sk_live_ and should be treated as a secret.

### Step 3: Send First Request
POST your HTML slide content to /api/export/jobs with your API key in the Authorization header. The API returns a jobId that you can use to track the export.

### Step 4: Download PPTX
Poll GET /api/export/jobs/{jobId} until status is "completed" (typically 5-15 seconds). The response includes a downloadUrl for the PPTX file. Use responseFormat: "base64" if you need the file content inline.

### curl Example
```bash
curl -X POST https://html2pptx.app/api/export/jobs \
  -H "Authorization: Bearer sk_live_xxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: my-unique-request-id-123" \
  -d '{
    "fileName": "quarterly-review.pptx",
    "html": "<section class=\"slide\" style=\"width:1600px;height:900px;padding:64px\"><h1>Hello</h1><p>Generated via API</p></section>",
    "css": ".slide { font-family: Arial, sans-serif; background: #fff; }",
    "autoEmbedFonts": false,
    "responseFormat": "url",
    "metadata": {
      "channel": "api",
      "source": "docs-quickstart"
    }
  }'

# Response (200 OK):
# {
#   "jobId": "5d934729-a0db-4aa9-bc65-e7a3e7e52b32",
#   "status": "queued",
#   "createdAt": "2026-04-02T10:30:00Z",
#   "fileName": "quarterly-review.pptx",
#   "slideCount": 1
# }
# Response headers include: x-request-id: req_abc123...

# Poll for completion:
curl -s https://html2pptx.app/api/export/jobs/5d934729-a0db-4aa9-bc65-e7a3e7e52b32 \
  -H "Authorization: Bearer sk_live_xxxx"

# Response (200 OK, when completed with responseFormat "url"):
# {
#   "jobId": "5d934729-a0db-4aa9-bc65-e7a3e7e52b32",
#   "status": "completed",
#   "createdAt": "2026-04-02T10:30:00Z",
#   "completedAt": "2026-04-02T10:30:12Z",
#   "fileName": "quarterly-review.pptx",
#   "slideCount": 1,
#   "mimeType": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
#   "downloadUrl": "https://storage.example.com/quarterly-review.pptx?token=..."
# }
```

### JavaScript Example
```javascript
const response = await fetch("https://html2pptx.app/api/export/jobs", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_live_xxxx",
    "Content-Type": "application/json",
    "Idempotency-Key": "my-unique-request-id-123",
  },
  body: JSON.stringify({
    fileName: "quarterly-review.pptx",
    html: `<section class="slide" style="width:1600px;height:900px">
  <h1>Hello World</h1>
  <p>Generated via API</p>
</section>`,
    css: ".slide { font-family: Arial, sans-serif; background: #fff; }",
    autoEmbedFonts: false,
    responseFormat: "url",
    metadata: { channel: "api", source: "docs-js" },
  }),
});

const { jobId } = await response.json();
const requestId = response.headers.get("x-request-id");
console.log("Job created:", jobId, "Request ID:", requestId);

// Poll for completion
const poll = async (id) => {
  const res = await fetch(`https://html2pptx.app/api/export/jobs/${id}`, {
    headers: { "Authorization": "Bearer sk_live_xxxx" },
  });
  const data = await res.json();
  if (data.status === "completed") return data;
  if (data.status === "failed") throw new Error(data.message || data.error);
  await new Promise(r => setTimeout(r, 2000));
  return poll(id);
};

const completed = await poll(jobId);
// With responseFormat "url", use downloadUrl directly
console.log("Download URL:", completed.downloadUrl);
// With responseFormat "base64", decode fileBase64
// const bytes = Uint8Array.from(atob(completed.fileBase64), c => c.charCodeAt(0));
```

### Python Example
```python
import requests
import time

API_KEY = "sk_live_xxxx"
BASE_URL = "https://html2pptx.app"

# 1. Create export job
resp = requests.post(
    f"{BASE_URL}/api/export/jobs",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
        "Idempotency-Key": "my-unique-request-id-123",
    },
    json={
        "fileName": "quarterly-review.pptx",
        "html": '<section class="slide" style="width:1600px;height:900px"><h1>Hello</h1></section>',
        "css": ".slide { font-family: Arial, sans-serif; }",
        "autoEmbedFonts": False,
        "responseFormat": "url",
        "metadata": {"channel": "api", "source": "docs-python"},
    },
)
job_id = resp.json()["jobId"]
request_id = resp.headers.get("x-request-id")
print(f"Job created: {job_id} (request-id: {request_id})")

# 2. Poll for completion
while True:
    status_resp = requests.get(
        f"{BASE_URL}/api/export/jobs/{job_id}",
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    data = status_resp.json()
    if data["status"] == "completed":
        break
    if data["status"] == "failed":
        raise RuntimeError(data.get("message") or data.get("error"))
    time.sleep(2)

# 3. Download the PPTX file (responseFormat "url")
download_resp = requests.get(data["downloadUrl"])
with open("output.pptx", "wb") as f:
    f.write(download_resp.content)
print("Saved to output.pptx")
```

## API Reference

Base URL: https://html2pptx.app
All request and response bodies use application/json. The create endpoint accepts top-level html/css/fileName fields plus optional width/height/layout controls; there is no nested payload wrapper.

### Authentication
All commercial API endpoints require authentication. Include your API key in one of the following headers. Keys are scoped per environment (test vs. production) and can be rotated from the Dashboard.

- **Authorization**: `Bearer sk_live_xxxx` — Recommended -- standard Bearer token format used by most HTTP clients and libraries
- **X-API-Key**: `sk_live_xxxx` — Alternative header for environments where Authorization is reserved (e.g., API gateways, proxies)

### Rate Limiting
Every REST API response includes headers that describe your current per-minute window, daily limit, and monthly fair-use status. Limits are enforced per API key for REST calls and per authenticated principal for remote MCP calls.

| Header | Description |
|--------|-------------|
| `x-request-id` | Unique request identifier included in every API response. Useful for debugging and when contacting support. |
| `X-Plan-Id` | The effective plan ID applied to the request. |
| `X-RateLimit-Limit` | Maximum requests allowed in the current one-minute window. |
| `X-RateLimit-Remaining` | Requests remaining in the current window. |
| `Retry-After` | Seconds to wait before retrying after a 429 response. |
| `X-Daily-Limit` | Returned on plans with a daily export cap. |
| `X-Daily-Remaining` | Remaining jobs in the current UTC day. |
| `X-Monthly-Used` | Exports accepted in the current UTC month. |
| `X-Fair-Use-State` | Monthly fair-use status such as normal, review, or upgrade_recommended. |

### Job Lifecycle Notes
- POST /api/export/jobs returns immediately with a queued job descriptor. It does not block until the PPTX is finished.
- Use the public status route at GET /api/export/jobs/{jobId}. Do not rely on any upstream worker URL that may appear in internal payloads.
- The completed REST response currently includes fileBase64 and mimeType. Decode fileBase64 to write the PPTX to disk or return it to the browser.
- Job ownership is bound to the API key or authenticated MCP principal that created the job. A different key cannot read the same jobId.
- Slide count is derived server-side from sanitized .slide roots. Client-provided counts are ignored for enforcement.

### Endpoints

#### POST /api/v1/import/pptx
Converts an existing .pptx into editable HTML slides (the reverse of export). Resolves theme colors (including clrMap/clrMapOvr inversion on dark slides), master text styles, and font families. Synchronous — returns the HTML in a single response. Also available at POST /api/import/pptx.

**Request Body**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `file` | file | No | multipart/form-data: the .pptx file (max 25 MB). Use this OR pptxBase64. |
| `pptxBase64` | string | No | application/json: base64-encoded .pptx contents (data URLs accepted). Recommended for JSON-RPC / MCP clients. |
| `fileName` | string | No | Optional original file name used for labeling. |

**Error Codes**

- `400`: Missing/invalid file, invalid base64, or invalid OOXML.
- `401`: Missing API key. Set the Authorization: Bearer or X-API-Key header.
- `403`: API key is not mapped to a plan with API access.
- `413`: PPTX exceeds the 25 MB size limit.

**Response (200 OK)**
```json
{
  "fileName": "deck.pptx",
  "plan": "api_starter",
  "slideCount": 13,
  "slides": [{ "index": 1, "html": "<section class=\"slide\">...</section>" }],
  "html": "<!doctype html>...",
  "css": "...",
  "warnings": []
}
```

#### POST /api/export/jobs
Creates a new PPTX export job from top-level HTML/CSS fields plus optional presentation size controls. The response is a queued job descriptor; use GET /api/export/jobs/{jobId} to retrieve terminal results.

**Request Body**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `fileName` | string | No | Output filename for the generated PPTX. Must end with .pptx extension. |
| `html` | string | Yes | HTML content containing one or more elements with .slide class. Each .slide becomes one PPTX slide. Required. |
| `css` | string | No | Optional CSS applied globally to the submitted HTML. |
| `autoEmbedFonts` | boolean | No | Attempt to detect and embed fonts into the generated PPTX. |
| `width` | number | No | Optional PPTX slide width in inches. Use with height for custom presentation sizes. |
| `height` | number | No | Optional PPTX slide height in inches. Use with width for custom presentation sizes. |
| `layout` | string | No | Optional PPTX layout preset or custom layout name. Common presets: LAYOUT_16x9, LAYOUT_16x10, LAYOUT_4x3, LAYOUT_WIDE. |
| `metadata` | object | No | Opaque metadata forwarded to the worker. Useful for request tracing on your side. |
| `responseFormat` | string | No | Controls how the completed PPTX file is delivered. "url" returns a presigned download URL (default). "base64" returns the file inline as base64. "both" returns both. Replaces the deprecated includeFileBase64 parameter. |
| `callbackUrl` | string | No | An HTTPS URL to receive a webhook POST when the job completes or fails. The worker sends the full job result to this URL with an x-signature-sha256 HMAC header for verification. Only https:// URLs are accepted. |

**Error Codes**

- `400`: Invalid request body -- missing required fields or malformed JSON.
- `401`: Missing or invalid API key. Ensure the Authorization or X-API-Key header is set with a valid sk_live_ key.
- `403`: API key does not have permission for this operation. Check plan limits or key scope.
- `413`: Request entity too large. The total request body exceeds your plan limit or the worker hard cap.
- `422`: The sanitized HTML resolves to more slides than your plan allows.
- `429`: Rate limit exceeded, daily limit exceeded, monthly fair-use review triggered, or concurrent job limit exceeded. Check Retry-After and usage headers.
- `502`: Bad gateway -- the worker backend is temporarily unavailable. Retry after a short delay.
- `503`: Service unavailable -- the system is under maintenance or experiencing high load. Retry with exponential backoff.

**Response (200 OK)**
```json
{
  "jobId": "5d934729-a0db-4aa9-bc65-e7a3e7e52b32",
  "status": "queued",
  "createdAt": "2026-04-02T10:30:00Z",
  "fileName": "quarterly-review.pptx",
  "slideCount": 1
}
```

#### GET /api/export/jobs/{jobId}
Retrieves the current status of an export job. Poll this endpoint until status is "completed" or "failed". When the job completes, the REST API returns the PPTX as fileBase64.

**Path Parameters**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `jobId` | string | Yes | The job ID returned from the POST /api/export/jobs endpoint. |

**Status Values**

- `queued`: Job is waiting in the processing queue.
- `processing`: Worker is actively converting HTML to PowerPoint.
- `completed`: Conversion finished successfully. fileBase64 and mimeType are available.
- `failed`: Conversion failed. The message field contains a human-readable description.

**Error Codes**

- `401`: Missing or invalid API key.
- `404`: Job not found -- either the jobId is invalid or the job belongs to a different API key.
- `429`: Status polling rate limit exceeded.

**Response (200 OK)**
```json
{
  "jobId": "5d934729-a0db-4aa9-bc65-e7a3e7e52b32",
  "status": "completed",
  "createdAt": "2026-04-02T10:30:00Z",
  "completedAt": "2026-04-02T10:30:12Z",
  "fileName": "quarterly-review.pptx",
  "slideCount": 3,
  "mimeType": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
  "downloadUrl": "https://storage.example.com/quarterly-review.pptx?token=..."
}
```

#### GET /api/export/plans
Returns the public plan catalog plus the recommended default plan. No authentication required.

**Response (200 OK)**
```json
{
  "recommendedPlanId": "founding_beta",
  "plans": [
    {
      "id": "free_web",
      "name": "Free Preview",
      "includes": { "api": true, "skills": true, "mcp": true },
      "limits": {
        "requestsPerMinute": 3,
        "dailyRequestLimit": 10,
        "monthlyRequestLimit": 10,
        "monthlyReviewThreshold": 0,
        "monthlyUpgradePromptThreshold": 0,
        "maxSlidesPerJob": 20,
        "concurrentJobs": 1,
        "apiKeys": 1,
        "maxPayloadBytes": 1048576
      }
    }
  ],
  "note": "Free Preview is generous for personal use. Paid tiers unlock commercial operation, team sharing, automation throughput, and support."
}
```

#### GET /api/openapi.json
Returns the OpenAPI 3.x specification for the html2pptx.app API. Useful for generating client SDKs, importing into Postman, or browsing the API schema.

**Response (200 OK)**
```json
// Returns the full OpenAPI 3.x JSON document
```

### HTML Contract
The HTML you send must follow these rules for reliable conversion.

- Each slide must have the class .slide -- this is the boundary marker for slide separation
- Each .slide must have explicit dimensions. 1600px x 900px (16:9 ratio at 13.333in x 7.5in) is the default example, and API/MCP callers can also set width, height, or layout for portrait/custom output
- Supported CSS: flexbox, grid, linear-gradient, radial-gradient, box-shadow, text-shadow, border-radius, transform (rotate, scale, translate, skew), opacity
- Fonts: system fonts (Arial, Helvetica, Noto Sans JP) work by default. Enable autoEmbedFonts for Google Fonts or custom @font-face declarations
- Images: both base64 data URIs and absolute URLs are supported. Relative paths will fail -- always use absolute URLs
- SVGs: inline SVG elements are supported and are converted to high-quality PNG images
- Avoid: script tags, iframes, canvas elements, anchor tags, form elements, SVG external references, CSS animations, @keyframes, and runtime-dependent state
- Nesting: deeply nested elements (> 10 levels) may impact output quality. Keep your HTML structure flat where possible
- Text wrapping: text boxes default to no-wrap to prevent unexpected line breaks in PPTX. If you need text to wrap within a container (e.g. long paragraphs), add white-space: normal to that element

### Supported HTML Elements
Each HTML element is converted to the most appropriate PowerPoint object for maximum editability.

| HTML Element | PPTX Output | Notes |
|-------------|-------------|-------|
| div, section, article | Shape with fill | Background colors, gradients, borders, and rounded corners are preserved. |
| p, h1-h6, span, b, em, strong, i, small | Text box | Text is fully editable in PowerPoint. Font size, weight, style, color, alignment, and line-height are all converted. Inline elements (span, b, em, etc.) become styled text runs within the same text box. |
| img | Image | Supports absolute URLs and base64 data URIs. CSS object-fit (contain, cover, fill, scale-down) and object-position are respected. Rounded corners are applied via clipping. |
| table, tr, td, th | Native PPTX table | Full table support with cell-level text styling, background fill, borders (solid/dashed/dotted), padding, text alignment, and colspan/rowspan. |
| ul, ol, li | Bulleted / Numbered list | Simple lists become editable bullet or numbered lists. Complex lists (with images or flex/grid inside) are converted as images. |
| svg | Image (PNG) | SVGs are converted to high-quality PNG images. |
| canvas | Image (PNG) | Canvas content is embedded as a PNG image. |
| Icon elements (FontAwesome, Material Icons, etc.) | Image | Icon fonts are automatically detected and converted to images. |

### Forbidden Elements
The following elements are stripped during input sanitization for security and compatibility:

- `script, iframe, object, embed` — Security: active content removed
- `link, meta, base` — Security: external references removed
- `form` — Interactive elements not supported in PPTX
- `style` — Use inline styles or the css parameter instead
- `a` — Anchor tags stripped for security
- `foreignobject, image (SVG), feimage, use` — SVG external references removed
- `animate, animateMotion, animateTransform, set, discard, mpath` — SVG animations not supported

### Supported CSS Features

- **Layout**: display: flex, display: grid, position: absolute/relative, gap, align-items, justify-content
- **Box Model**: padding, margin, width, height, box-sizing, overflow: hidden
- **Background**: background-color, linear-gradient(), radial-gradient(), background-image (URL/base64)
- **Border**: border, border-radius (including per-corner), border-color, border-width
- **Shadow**: box-shadow (single and multiple), text-shadow
- **Typography**: font-family, font-size, font-weight, color, text-align, line-height, letter-spacing
- **Transform**: transform: rotate(), scale(), translate(), skew()
- **Visual**: opacity, visibility, z-index, object-fit

### Error Response Format
All error responses follow the RFC 9457 Problem Details format with additional legacy fields for backwards compatibility:
```json
{
  "type": "https://html2pptx.app/errors/slides-limit-exceeded",
  "status": 422,
  "title": "Slides limit exceeded",
  "detail": "Plan Starter supports up to 200 slides per job. You submitted 260 slides.",
  "instance": "/api/export/jobs",
  "error": "slides_limit_exceeded",
  "message": "Plan Starter supports up to 200 slides per job.",
  "slideCount": 260
}
```

## Three Integration Channels

### REST API
Standard HTTP endpoints for creating HTML-to-PPTX export jobs and polling status. Best for backend integrations, internal tools, and SaaS embedding. Works with any language -- curl, JavaScript, Python, Go, Ruby, and more. Template publishing is not a REST API surface.

### Skills
Register the html2pptx skill for agent tools like Claude Code and Codex. The agent can diagnose, rewrite, export slide-safe HTML, open local editing, and publish HTML template drafts through the built-in remote MCP workflow. Ideal for AI-powered workflows where the agent manages the full pipeline.

### MCP (Model Context Protocol)
Expose the backend to AI agents via the MCP protocol. Use the remote HTTP endpoint at /mcp for export, docs, catalog, and template publishing tools; use local stdio MCP only for opening local HTML in edit-slide. HTML template drafts must be created through remote MCP after validation.

## Skills Integration
Skills are packaged capabilities that extend AI coding agents with domain-specific knowledge and workflows. The html2pptx.app skill teaches your agent how to author slide-safe HTML, validate it against the PPTX conversion contract, optionally open the local visual editor, export through remote or local MCP workflows, and publish HTML template drafts through its built-in remote MCP publishing workflow. Install once, and your agent can convert natural language instructions into production-ready PowerPoint files or creator-owned HTML drafts.

### Setup

#### Step 1: Install MCP + Skill
Pick the command for the agent you actually use: Claude Code, Codex, Cursor, VS Code (GitHub Copilot), or Antigravity. For Grok Build, use the Grok-specific installer. For other supported agents or multiple targets, drop the `-a` flag and use the interactive selector. Avoid `--yes` unless you intentionally want to install into every detected agent directory.

```bash
# Choose the command for your agent
# Claude Code
npx skills add https://html2pptx.app -a claude-code

# Grok Build
npx --yes --package html2pptx-local-mcp@latest html2pptx-install-skills grok

# Codex
npx skills add https://html2pptx.app -a codex

# Cursor
npx skills add https://html2pptx.app -a cursor

# VS Code (GitHub Copilot)
npx skills add https://html2pptx.app -a github-copilot

# Antigravity
npx skills add https://html2pptx.app -a antigravity

# Preview published skills without installing
npx skills add https://html2pptx.app --list

# More agents / multiple targets: use the interactive selector
npx skills add https://html2pptx.app

# Claude Code / Codex / Grok Build users: run the matching one line for MCP.
npx --yes --package html2pptx-local-mcp@latest html2pptx-install-mcp claude
npx --yes --package html2pptx-local-mcp@latest html2pptx-install-mcp codex
npx --yes --package html2pptx-local-mcp@latest html2pptx-install-mcp grok
```

#### Step 2: Configure API key
Create an API key in the html2pptx.app dashboard and set it as an environment variable.

```bash
# Set API key as environment variable
export HTML2PPTX_API_KEY="sk_live_xxxx"

# Or add to your .env file
echo 'HTML2PPTX_API_KEY=sk_live_xxxx' >> .env
```

#### Step 3: Try it out
Launch your editor and give it a natural language instruction to create slides. The skill handles everything automatically.

```bash
# 例: Claude Code でスライド作成 → PPTX出力

> 「この会議メモから5枚のプレゼンを作って、PPTXで出力して」

# エージェントが自動で実行するフロー:
# 1. SKILL.md を読み込み、html2pptx.app のHTML契約を理解
# 2. 会議メモを解析し、スライド構成を設計
# 3. .slide クラス + 明示サイズ付きのスライドセーフHTMLを生成（1600x900 はデフォルト例）
# 4. diagnose でマークアップを検証（safe / needs-rewrite / out-of-scope）
# 5. html2pptx.app API にエクスポートジョブを送信
# 6. 完了をポーリングし、completed payload をユーザーに返却

# APIキーの設定（環境変数）
export HTML2PPTX_API_KEY="sk_live_xxxx"
```

### Workflow
1. Agent receives a user request (e.g., "Create a deck from these meeting notes")
2. Agent reads the skill definition to understand the html2pptx.app HTML contract
3. Agent generates slide-safe HTML with .slide class elements and explicit dimensions. 1600x900 is the default example
4. Agent validates the markup against the conversion contract
5. If visual review is needed, the agent opens the local edit-slide editor through the CLI or local stdio MCP, then re-reads the edited HTML from disk
6. Agent connects to remote MCP or local stdio MCP and calls html2pptx_create_export_job
7. Agent polls with html2pptx_wait_for_export_job until completed
8. If the user wants to create an HTML template draft, the agent uses the html2pptx skill and remote MCP: infer title/tags from the HTML, run AI security preflight, validate, fix errors, save a draft, then return draftUrl for dashboard review
9. Agent returns the completed job summary to the user

- **Diagnose HTML**: Classify markup as safe, needs-rewrite, or out-of-scope before attempting export. Catches issues like missing .slide elements, unsupported CSS, or dynamic content.
- **Rewrite Markup**: Transform web-shaped HTML (responsive layouts, percentage-based sizing, scroll containers) into fixed-size .slide structures suitable for PPTX conversion.
- **Generate Slides**: Create new slide-safe HTML from scratch given a text prompt, topic outline, or data payload. Applies best practices for visual hierarchy and readability.
- **Validate Output**: Run the generated HTML through a pre-flight check against the html2pptx.app HTML contract before making the API call, preventing wasted export quota on invalid input.
- **Publish Templates**: For marketplace HTML drafts, the html2pptx skill includes AI security preflight, remote MCP validation, and draft creation. Web, CLI, local MCP, and generic REST flows do not create template drafts.

## MCP Integration
MCP (Model Context Protocol) is an open protocol that exposes backend capabilities to AI agents through a standardized tool interface. html2pptx.app supports two MCP surfaces: the remote HTTP MCP endpoint at /mcp for export, usage, docs, templates, catalog, and HTML template publishing workflows, and the local stdio MCP server for export tools plus local edit-slide sessions through a localhost bridge. Use remote MCP when the agent needs to convert HTML to PPTX or create an HTML template draft. Use local stdio MCP only when the agent must open, preview, or edit a local HTML file on the user machine; local MCP does not publish templates.

Install: `npx --yes --package html2pptx-local-mcp@latest html2pptx-install-mcp claude`

### Available MCP Tools

- `html2pptx_list_export_plans` — List the current commercial plan catalog and recommended plan.
- `html2pptx_create_export_job` — Create an export job from HTML/CSS content. Supports optional width, height, layout, waitForCompletion, timeoutMs, and responseFormat ("url" | "base64" | "both").
- `html2pptx_import_pptx` — Reverse of export: convert an existing .pptx into editable HTML slides. Pass the file as pptxBase64 (works on remote MCP); the local stdio MCP also accepts filePath. Resolves theme colors, master text styles, and fonts.
- `html2pptx_get_export_job` — Get the current status of an export job by jobId.
- `html2pptx_wait_for_export_job` — Poll until the job completes or fails. Handles retries and backoff inside the tool.
- `html2pptx_get_docs` — Fetch html2pptx.app documentation to understand the API contract, HTML requirements, and integration guides.
- `html2pptx_get_usage` — Fetch the current usage and quota status for your plan. Shows weekly export count, remaining quota, plan limits, and reset timing.
- `html2pptx_list_templates` — List available marketplace templates with metadata and optional category filtering.
- `html2pptx_get_template_html` — Fetch a template source HTML and design prompt so agents can study or remix it.
- `html2pptx_validate_template_html` — Dry-run marketplace HTML validation after AI security preflight. Required before creating an HTML template draft.
- `html2pptx_publish_template` — Upload validated HTML, infer missing title/description/category/tags, and create a creator-owned HTML draft by default. The tool returns draftUrl; the user reviews and presses the final publish button in the dashboard.
- `html2pptx_open_local_slide_editor` — Local stdio MCP only. Starts the existing CLI localhost bridge for a local .html/.htm slide file and opens the no-code editor without publishing the HTML. Not available from remote /mcp because remote servers cannot access user files.
- `html2pptx_stop_local_slide_editor` — Local stdio MCP only. Stops a local editor bridge session started by html2pptx_open_local_slide_editor.

## Use Cases & Examples
html2pptx.app is designed for automated, repeatable slide generation. Here are the most common integration patterns:

### Automated Quarterly Reports
Generate quarterly performance decks from live data. Pull metrics from your database, format them as slide HTML with charts and KPI cards, and export via the API. Schedule with cron or trigger from your BI pipeline for fully hands-off reporting.
```javascript
const slides = quarterly_data.map((quarter, i) => `
  <section class="slide" style="width:1600px;height:900px;padding:60px;font-family:'Noto Sans JP',sans-serif;">
    <h2 style="color:#1a1a2e;font-size:36px;">Q${i+1} Results</h2>
    <div style="display:grid;grid-template-columns:1fr 1fr;gap:40px;margin-top:40px;">
      <div style="background:#f0f4ff;border-radius:16px;padding:32px;">
        <p style="font-size:14px;color:#6b7280;">Revenue</p>
        <p style="font-size:48px;font-weight:700;color:#1a1a2e;">${quarter.revenue}</p>
      </div>
      <div style="background:#f0fdf4;border-radius:16px;padding:32px;">
        <p style="font-size:14px;color:#6b7280;">Growth</p>
        <p style="font-size:48px;font-weight:700;color:#16a34a;">${quarter.growth}%</p>
      </div>
    </div>
  </section>
`).join("\n");

const resp = await fetch("/api/export/jobs", {
  method: "POST",
  headers: { "Authorization": "Bearer sk_live_xxxx", "Content-Type": "application/json" },
  body: JSON.stringify({ fileName: "q-report.pptx", html: slides }),
});
```

### Sales Proposal Templates
Define brand-compliant slide templates in HTML/CSS once, then populate them with dynamic content for each campaign or client pitch. Variables like company name, project details, and pricing are injected at generation time. Marketing teams maintain the templates; sales reps get pixel-perfect branded decks instantly.
```javascript
// Sales proposal template with dynamic client data
function generateProposal(client) {
  return `
    <section class="slide" style="width:1600px;height:900px;padding:60px;background:linear-gradient(135deg,#1a1a2e,#16213e);">
      <h1 style="color:#fff;font-size:48px;">${client.companyName} 御中</h1>
      <p style="color:#a0aec0;font-size:24px;margin-top:20px;">ご提案書 - ${client.projectName}</p>
      <div style="position:absolute;bottom:60px;left:60px;color:#718096;font-size:14px;">
        ${new Date().toLocaleDateString('ja-JP')} | Confidential
      </div>
    </section>
    <section class="slide" style="width:1600px;height:900px;padding:60px;">
      <h2 style="font-size:36px;color:#1a1a2e;">提案概要</h2>
      <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:30px;margin-top:40px;">
        ${client.features.map(f => `
          <div style="background:#f7fafc;border-radius:12px;padding:24px;">
            <h3 style="font-size:20px;color:#2d3748;">${f.title}</h3>
            <p style="font-size:14px;color:#718096;margin-top:8px;">${f.description}</p>
          </div>
        `).join('')}
      </div>
    </section>
  `;
}
```

### Agent-Powered Presentations
Let AI agents create presentation decks from meeting notes, research summaries, or project briefs. Using Skills or MCP integration, the agent understands the html2pptx.app HTML contract, generates compliant slides, and delivers a download link. Users simply describe what they want in natural language.

### SaaS Export Embedding
Add "Export to PowerPoint" functionality to your SaaS product. Render your app's dashboards, analytics views, or reports as slide HTML and call the html2pptx.app API from your backend. Users get native PPTX files with editable text and shapes -- not flat screenshots.
```javascript
// Backend route: POST /api/dashboard/export-pptx
app.post("/api/dashboard/export-pptx", async (req, res) => {
  const { dashboardId } = req.body;
  const dashboard = await getDashboard(dashboardId);

  // Render each widget as a slide
  const slides = dashboard.widgets.map(widget => `
    <section class="slide" style="width:1600px;height:900px;padding:40px;">
      <h2 style="font-size:28px;color:#1a1a2e;">${widget.title}</h2>
      <div style="margin-top:20px;">${widget.renderToHTML()}</div>
    </section>
  `).join("");

  // Call html2pptx.app API
  const job = await fetch(process.env.HTML2PPTX_API_URL + "/api/export/jobs", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.HTML2PPTX_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      fileName: `${dashboard.name}.pptx`,
      html: slides,
    }),
  });

  const { jobId } = await job.json();
  res.json({ jobId, statusUrl: `/api/export/jobs/${jobId}` });
});
```

## Plans & Pricing
Choose the plan that fits your usage. The current public catalog is defined in code and enforced in the API gateway: requests per minute, daily guardrails, maximum slides per job, concurrent jobs, API key count, and payload size all vary by plan.

| Plan | Exports | Slides | Support | Price |
|------|---------|--------|---------|-------|
| Free Preview | 10 per month / 3 rpm | 20 per job | Community | ¥0 |
| Founder Beta | 300 per month / 5 rpm | 50 per job | Self-serve | ¥980/mo |
| Starter | 3,000 per month / 15 rpm | 100 per job | Email | ¥2,980/mo |
| Business | 20,000 per month / 60 rpm | 200 per job | Priority | ¥9,800/mo |
| Enterprise / OEM | Custom | 500+ per job | Dedicated | ¥49,800/mo〜 |

Upgrade anytime from the Dashboard. Changes take effect immediately with prorated billing. Downgrade at the end of the current billing period.

## Security & Limits
Public API, Skills, MCP, Studio, and hosted web export are all routed through the same security-sensitive conversion pipeline. The practical controls below are the ones that matter when you integrate or expose the product.

### Authentication and authorization
REST API uses API keys. Remote MCP supports commercial API keys or WorkOS-backed authenticated sessions. Job lookup is bound to the same API key or authenticated principal that created the job.

### SVG and untrusted markup
Public API and MCP sanitize incoming HTML. Inline SVG is converted to PNG images for reliable output.

### Worker isolation
Export jobs run in isolated contexts with enforced request body limits and automatic cleanup of expired jobs.

### Usage controls
Per-minute rate limiting, daily guardrails, monthly fair-use review thresholds, maximum slides per job, maximum payload size, and concurrent job limits are all enforced server-side based on the active plan.

### Recommended production practices
- Treat API keys as secrets and rotate them from the dashboard when they are exposed.
- Use the REST API for backend automation and same-origin hosted web export only for first-party browser flows.
- Poll the public job status route with backoff instead of hammering the status endpoint.
- Keep slide markup deterministic: explicit slide dimensions, predictable CSS, and no runtime-dependent content. 1600x900 remains the default example.
- With responseFormat: "base64", fileBase64 can be large; decode it in streaming or binary-safe code paths on your side.
- For agent integrations, decide whether the client should use local stdio MCP or remote /mcp before rollout.

## FAQ

**Q: How is html2pptx.app different from other HTML-to-PPTX solutions?**
Most alternatives take a screenshot of your HTML and embed it as a flat image in each slide. html2pptx.app produces fully editable PowerPoint output -- CSS properties like flexbox, gradients, border-radius, and shadows are faithfully reproduced. The result is editable text, high-quality shapes, and smaller file sizes.

**Q: Can I convert any HTML to PPTX?**
Not reliably. html2pptx.app is optimized for slide-oriented HTML with .slide class elements and explicit dimensions. 1600x900 is the default example, but portrait and other custom sizes are also supported. Arbitrary web pages, interactive apps, scroll-based layouts, and pages with JavaScript-dependent rendering are not supported. The HTML contract section describes the exact requirements.

**Q: What becomes a separate slide?**
Each element with the .slide class becomes one slide in the output PPTX. If your HTML contains 5 elements with class="slide", the output will have 5 slides. Define clear slide boundaries for predictable results.

**Q: Will exported content remain editable in PowerPoint?**
Yes, in most cases. Text stays fully editable and shapes remain adjustable in PowerPoint. Inline SVG is converted to high-quality PNG images for reliable output.

**Q: How long does export take?**
Most single-slide jobs complete in 3-5 seconds. Multi-slide decks (10-50 slides) typically take 8-20 seconds depending on complexity, image count, and font embedding. The worker processes slides in parallel where possible. Poll the job status endpoint every 2 seconds for optimal responsiveness.

**Q: Which fonts are supported?**
System fonts (Arial, Helvetica, Times New Roman, etc.) work by default. For web fonts, enable autoEmbedFonts: true -- html2pptx.app will download the font files from Google Fonts or your custom @font-face URLs and embed them into the PPTX. Japanese fonts like Noto Sans JP, Yu Gothic, Meiryo, and Hiragino are fully supported.

**Q: Is there a free plan?**
Yes. The current public catalog includes an Early Access tier with limited API, Skills, and MCP usage. Check GET /api/export/plans for the current plan metadata because limits are enforced from code and may evolve during early rollout.

**Q: Can I use SVGs in my slides?**
Yes. Inline SVG is supported and is converted to high-quality PNG images for reliable output across all PowerPoint environments.

**Q: What is the maximum file size?**
The HTML payload should stay under 5MB. Generated PPTX files vary by content but typically range from 100KB to 10MB. Jobs with many high-resolution images embedded as base64 will produce larger files. Consider using URL references for large images.

**Q: How secure is the service?**
html2pptx.app implements multiple security layers: jobs are bound to the creating principal; API keys are hashed at rest; request body limits and concurrent job limits are enforced server-side. Use the REST API for server-side automation and treat hosted web export as a browser surface.

**Q: Does html2pptx.app support Japanese text and CJK characters?**
Yes, fully. Japanese, Chinese, and Korean characters render correctly. For best results, specify a CJK font in your CSS (e.g., font-family: "Noto Sans JP", sans-serif) and enable autoEmbedFonts to ensure portable rendering on machines without the font installed.

**Q: How do I handle errors?**
Check the job status endpoint. If status is "failed", the error field contains a human-readable description. All API errors return a structured JSON body following RFC 9457 Problem Details format with type, status, title, detail, and instance fields, plus legacy error and message fields for backwards compatibility. Common issues: missing .slide elements (400), expired API key (401), rate limit exceeded (429), oversized content (413).

**Q: Can I use CSS Grid for complex slide layouts?**
Yes. CSS Grid is fully supported including grid-template-columns, grid-template-rows, gap, and grid placement properties. This makes it easy to create multi-column layouts, dashboard-style cards, and complex visual arrangements that convert cleanly to PPTX.

**Q: Is there a webhook for job completion?**
Yes. Add a callbackUrl field (HTTPS only) to your POST /api/export/jobs request. The worker will POST the full job result to your callback URL when the job completes or fails, with an x-signature-sha256 HMAC header for verification. Alternatively, you can still use polling on GET /api/export/jobs/{jobId} with a 2-second interval. For MCP users, html2pptx_wait_for_export_job handles polling automatically.

### Troubleshooting

**Job stuck in "queued" status**
The private worker may be offline or overloaded. Wait 30 seconds and retry. If persistent, check worker health from the Dashboard or contact support.

**Slides appear blank**
Ensure your HTML contains elements with class="slide" and that those elements have visible content. Also verify that CSS is included in the payload and not relying on external stylesheets.

**Fonts look different in PPTX**
Enable autoEmbedFonts: true to embed web fonts. If using custom fonts, ensure the @font-face URLs are publicly accessible. Fallback to system-safe fonts like Arial or Noto Sans for maximum compatibility.

**429 Rate limit error**
Check the X-RateLimit-Reset header for when your window resets. Implement exponential backoff in your polling logic. Upgrade your plan for higher request limits.

**Layout differs from browser preview**
Use explicit dimensions on .slide elements with inline styles. 1600x900 is the default example, but custom aspect ratios also work when your slide HTML and requested width/height/layout match. Avoid responsive/percentage-based layouts, media queries, and viewport-relative units (vh, vw).

**Images not appearing in PPTX**
Use absolute URLs (https://...) or base64 data URIs for images. Relative paths and localhost URLs will fail. Ensure image URLs are publicly accessible from the worker.

**PPTX file size is too large**
Large files are usually caused by embedded base64 images or image-heavy content. Use URL references instead, or compress images before embedding.

## How html2pptx.app Compares

| Feature | html2pptx | Others |
|---------|-----------|--------|
| Conversion method | Fully editable PowerPoint output | Screenshot/raster image per slide |
| Text editability | Fully editable text boxes | Flat image -- no text editing |
| CSS support | Flexbox, Grid, gradients, shadows, transforms | Limited or none |
| SVG handling | Converted to high-quality PNG images | Converted to PNG |
| File size | Usually compact, depends on embedded imagery | Large (embedded images) |
| Font embedding | Automatic web font embedding | Not supported |

## Templates

html2pptx.app provides free, fully editable PowerPoint templates generated from HTML/CSS. All text, shapes, and layouts are natively editable in PowerPoint.

Each template includes a design prompt that describes the exact design direction, layout patterns, color palette, and CSS techniques — enabling AI agents to reproduce or customize the design.

Template publishing is HTML-only and remote-MCP-only. Web UI, CLI, local MCP, and generic REST API flows cannot create marketplace drafts, and PPTX is not a publishing source. HTML drafts must go through remote MCP so an agent can follow the html2pptx skill, infer title/description/category/tags from the HTML when the user did not provide them, run an AI security preflight on raw HTML for prompt-injection, hidden instructions, phishing/social-engineering copy, credential or API-key requests, terminal/API commands, and exfiltration attempts, then run `html2pptx_validate_template_html`, fix policy errors, and call `html2pptx_publish_template` with a WorkOS-bound user token and `visibility: "draft"`. The tool uploads the HTML source, saves a creator-owned draft, and returns `draftUrl`; the user should review the draft and press the final publish button in the dashboard. Installing the html2pptx skill is sufficient for export, local editing, template browsing, and HTML template publishing.

### Templates API

- List all templates: `GET /api/templates`
- Get single template with prompt: `GET /api/templates?id={templateId}`
- Include HTML source: `GET /api/templates?id={templateId}&include=html`
- Include prompts in list: `GET /api/templates?include=prompt`

### Templates via MCP

- `html2pptx_list_templates` — Browse all templates
- `html2pptx_get_template_html` — Get HTML source + design prompt for a template
- `html2pptx_validate_template_html` — Dry-run marketplace HTML validation after the agent has completed the AI security preflight. Fix every error before publishing.
- `html2pptx_publish_template` — Upload preflight-reviewed and validated HTML, infer missing metadata when needed, and create a creator-owned draft only. Remote MCP never creates an unlisted share link or public gallery listing; final sharing/publishing happens from the user dashboard. This remote MCP tool is the only supported template draft-creation path. HTML previews prefer static PNG snapshots, fall back to script-disabled sandbox views, and source is private unless allowSourceView=true. HTML is checked against the template policy and scanned for AI-agent prompt-injection instructions and configured external scanners before dashboard sharing/publishing (returns draftUrl for review).

### Templates via CLI

- `html2pptx templates list` — Browse all templates
- `html2pptx templates get <id> --prompt` — Get template with design prompt
- `html2pptx templates get <id> --prompt --html --json` — Full template data as JSON
- `html2pptx templates publish` — Disabled. Template publishing is HTML-only via remote MCP.
- To create an HTML template draft, use remote MCP: AI security preflight -> `html2pptx_validate_template_html` -> `html2pptx_publish_template`.

- Templates gallery: https://html2pptx.app/templates
- Creator rewards: https://html2pptx.app/creator-rewards
- html2pptx skill: https://html2pptx.app/.well-known/skills/html2pptx/SKILL.md
- Edit-slide skill: https://html2pptx.app/.well-known/skills/open-slide/SKILL.md

## CLI Tool

Install: `npm install -g html2pptx-cli`

Commands: `html2pptx login`, `html2pptx convert <file>`, `html2pptx edit <file>`, `html2pptx status`, `html2pptx whoami`, `html2pptx logout`, `html2pptx config`, `html2pptx templates list`, `html2pptx templates get <id>`

Supports interactive mode (guided prompts) and direct mode (flags for scripting/CI/CD/AI agents). CLI export/editing is not marketplace publishing; template drafts are HTML-only and remote-MCP-only.

- npm: https://www.npmjs.com/package/html2pptx-cli

## Links

- Website: https://html2pptx.app
- Dashboard: https://html2pptx.app/dashboard
- Documentation: https://html2pptx.app/docs/en
- Templates: https://html2pptx.app/templates
- CLI: https://www.npmjs.com/package/html2pptx-cli
- Release Notes: https://html2pptx.app/releases
- Pricing: https://html2pptx.app/pricing
- OpenAPI: https://html2pptx.app/api/openapi.json
- MCP Endpoint: https://html2pptx.app/mcp
- Full LLM Documentation: https://html2pptx.app/llms-full.txt