Install
openclaw skills install htmlpixUse when the user wants to call, test, or integrate the HTMLPix HTML-to-image API — including auth setup, signed URL minting, image rendering, template CRUD,...
openclaw skills install htmlpixUse the API contracts below when generating code, curl commands, SDK wrappers, or troubleshooting responses.
https://api.htmlpix.comAuthorization: Bearer <API_KEY>hpx_ and managed at https://htmlpix.com/api-keysEvery private request goes through this pipeline:
Authorization: Bearer <key> headerapiKeys tableactive (otherwise 403 KEY_INACTIVE)quotas tableactive, trialing, or canceled with time remaining| Status | Code | Meaning |
|---|---|---|
401 | MISSING_API_KEY | No Authorization: Bearer header |
401 | INVALID_API_KEY | Key not found |
403 | KEY_INACTIVE | Key revoked or disabled |
402 | NO_SUBSCRIPTION | No quota record found |
402 | SUBSCRIPTION_INACTIVE | Subscription expired or past_due |
429 | QUOTA_EXCEEDED | Monthly mint quota exhausted |
/v1/url (private)Mint one signed image URL. The server resolves template variables, executes the template JSX, uploads the rendered VNode to Cloudflare R2/KV, and returns a signed URL pointing to the Cloudflare Worker that renders the final image.
Request JSON:
| Field | Type | Required | Constraints |
|---|---|---|---|
templateId | string | yes | max 128 chars |
width | integer | no | 1–4096, defaults to template value or 1200 |
height | integer | no | 1–4096, defaults to template value or 630 |
format | string | no | png, jpeg, or webp — defaults to template value or webp |
quality | integer | no | 0–100, defaults to template value |
devicePixelRatio | number | no | positive number, defaults to template value or 1 |
tv | string | no | max 128 chars, cache-busting version tag — defaults to template updatedAt |
variables | object | no | max 64 keys, key max 64 chars, each value max 4000 chars serialized. Values can be string, number, boolean, null, array, or nested object. |
Response 200:
{ "url": "https://image.htmlpix.com/v1/image?...&sig=...", "expiresAt": 1710345600000 }
Operational limits:
/v1/urls (private)Mint multiple signed image URLs in one request.
Request JSON:
{ "items": [ /* each item has same shape as POST /v1/url */ ] }
items.length must be 1–25Response 200:
{ "urls": [{ "templateId": "...", "url": "...", "expiresAt": 1710345600000 }] }
Operational limits:
/v1/image (public, signed — served by Cloudflare Worker)Requests to api.htmlpix.com/v1/image are 301-redirected to the Cloudflare Worker at image.htmlpix.com/v1/image. The Worker renders the image from VNode data stored in R2/KV.
Required query params:
| Param | Description |
|---|---|
templateId | Template identifier |
uid | User ID that minted the URL |
exp | Expiry timestamp (unix ms) |
sig | HMAC signature — invalidated if any param changes |
Optional query params:
| Param | Default | Description |
|---|---|---|
width | 1200 | Image width |
height | 630 | Image height |
format | webp | png, jpeg, or webp |
quality | — | 0–100 |
dpr | — | Device pixel ratio |
tv | — | Cache version tag |
rv | — | Render version |
v_<name> | — | Template variables as v_title=Hello |
Behavior:
403 URL_EXPIRED — URL past expiry403 INVALID_SIGNATURE — params modified after signing304 Not Modified via If-None-MatchImportant: treat minted URLs as opaque. If any query value changes, signature validation fails.
/v1/templates (private)List templates visible to the authenticated user.
Query params:
| Param | Default | Values |
|---|---|---|
scope | all | all, mine, starter |
Response 200:
{ "templates": [ /* template objects */ ] }
/v1/templates (private)Create a custom template. Templates are defined by a single code field containing JSX/TSX source code. The server compiles, validates, and extracts variables automatically.
Request JSON:
| Field | Type | Required | Constraints |
|---|---|---|---|
name | string | yes | max 120 chars |
description | string | no | max 2000 chars |
code | string | yes | max 180,000 chars — JSX/TSX template source |
Legacy fields jsx, variables, googleFonts, width, height, format are rejected with error code LEGACY_TEMPLATE_PAYLOAD. Use code only.
Response 201:
{ "templateId": "abc123..." }
Error responses:
400 COMPILE_ERROR — JSX compilation or validation failed400 LEGACY_TEMPLATE_PAYLOAD — sent a deprecated field/v1/templates/:templateId (private)Fetch one template visible to the caller.
Response 200:
{ "template": { /* template object */ } }
404 TEMPLATE_NOT_FOUND if not visible to caller/v1/templates/:templateId (private)Update template fields. At least one field required.
Request JSON:
| Field | Type | Required | Constraints |
|---|---|---|---|
name | string | no | max 120 chars |
description | string | no | max 2000 chars |
code | string | no | max 180,000 chars — JSX/TSX template source |
Legacy fields jsx, variables, googleFonts, width, height, format are rejected.
Response 200:
{ "templateId": "abc123..." }
Error responses:
400 EMPTY_UPDATE — no updatable field provided400 COMPILE_ERROR — JSX compilation failed404 TEMPLATE_NOT_FOUND — template doesn't exist or not owned by caller/v1/templates/generate (private)AI-assisted template generation. Always uses batch format.
Request JSON:
{
"items": [
{ "prompt": "A social card with bold title and gradient background", "width": 1200, "height": 630 }
]
}
| Field | Type | Required | Constraints |
|---|---|---|---|
items | array | yes | 1–5 items |
items[].prompt | string | yes | max 2000 chars |
items[].width | integer | no | 1–4096, default 1200 |
items[].height | integer | no | 1–4096, default 630 |
Response 200:
{
"results": [
{ "ok": true, "result": { /* generated template data */ } },
{ "ok": false, "error": "error message" }
]
}
Each item settles independently — some may succeed while others fail.
Error responses:
429 QUOTA_EXCEEDED — AI generation quota hit402 SUBSCRIPTION_REQUIRED — paid plan needed422 PARSE_FAILED — AI output couldn't be parsed502 AI_NOT_CONFIGURED — AI provider not set up502 GENERATION_FAILED — generic AI failurePOST /v1/url or /v1/urls on your backend.url directly (meta tags, email HTML, social cards, etc.).402, 429, and 503 with retries/fallback messaging.# Mint a single image URL
curl -X POST https://api.htmlpix.com/v1/url \
-H "Authorization: Bearer $HTMLPIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "tmpl_123",
"variables": { "title": "Launch Day" },
"width": 1200,
"height": 630,
"format": "png"
}'
# List your templates
curl -X GET "https://api.htmlpix.com/v1/templates?scope=mine" \
-H "Authorization: Bearer $HTMLPIX_API_KEY"
# Create a template from code
curl -X POST https://api.htmlpix.com/v1/templates \
-H "Authorization: Bearer $HTMLPIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "My Social Card",
"code": "export default function Template({ title }) {\n return <div style={{ fontSize: 48 }}>{title}</div>\n}"
}'
# AI-generate a template
curl -X POST https://api.htmlpix.com/v1/templates/generate \
-H "Authorization: Bearer $HTMLPIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [{ "prompt": "Minimalist blog post OG image with title and author" }]
}'
If the user asks for an endpoint not listed above, say it is not present in the current server route table and avoid inventing routes.