REST API documentation
Publish and update HTML pages straight from code and AI pipelines. Publish and update static sites and HTML pages from code and AI pipelines. Available on every plan, including Free, with an API key.
Authentication
Every request needs an API key in the Authorization header. Create the key in your dashboard on the “API keys” page — it is shown only once. A request without a valid key is rejected with 401 invalid_api_key.
The base address of every endpoint is https://htmlkin.io/api/v1. Add this header to each request:
"Authorization: Bearer <api_key>"The API is available on every plan, including Free. Create a key in your dashboard on the “API keys” page — it is shown only once.
Rate limits
Request rates are limited by plan, per account: all its keys share one counter. Over the limit you get 429 rate_limit_exceeded with a Retry-After header.
| Plan | Limit |
|---|---|
| Free | 10 requests per minute, up to 60 site uploads an hour together with the dashboard, one update per site a minute |
| Pro | 60 requests per minute |
| Business | 120 requests per minute |
Endpoints
Publish a page
Uploads an HTML file or a static site ZIP and publishes it on its own subdomain. Send exactly one of html_file and site_archive. A random subdomain is assigned by default; set your own in the subdomain field.
multipart/form-data| Field | Type | Required | Description |
|---|---|---|---|
| html_file | file | no | A single HTML file, saved as index.html. Exactly one content source. |
| site_archive | file | no | A static site ZIP: the entry page is the root index.html or the first HTML file in the archive root. The unpacked site must be up to 200 MB and fit in the free storage space. |
| subdomain | string | no | Preferred subdomain ({subdomain}.htmlkin.io), 3–63 characters a-z, 0-9, “-” (not at the ends). 409 if taken. |
| pin | string | no | A 4-digit PIN (0000–9999) to protect viewing. On paid plans. |
| visibility | string | no | Who can open the site: public — anyone, search engines index it; link — anyone with the link, not indexed; team — the account's team members after signing in, on the Business plan; private — only the account owner after signing in. Defaults to public. |
{
"id": "abc123",
"url": "https://mypage.htmlkin.io",
"expires_at": null,
"created_at": "2026-06-14T07:00:00Z",
"updated_at": "2026-06-14T07:00:00Z",
"file_count": 1,
"entry_path": "index.html",
"visibility": "public"
}Update a page
Replaces the whole site with new HTML or ZIP at the same address and/or changes the PIN and visibility. The page URL stays the same. Send at most one of html_file and site_archive; you can send only pin and/or visibility to change just protection or visibility.
multipart/form-data| Field | Type | Required | Description |
|---|---|---|---|
| html_file | file | no | A new HTML file (optional; not together with site_archive). |
| site_archive | file | no | A new complete site ZIP; all previous files are replaced. |
| pin | string | no | 4 digits set or change the PIN; an empty string removes it. |
| visibility | string | no | Who can open the site: public — anyone, search engines index it; link — anyone with the link, not indexed; team — the account's team members after signing in, on the Business plan; private — only the account owner after signing in. |
{
"id": "abc123",
"url": "https://mypage.htmlkin.io",
"expires_at": null,
"created_at": "2026-06-14T07:00:00Z",
"updated_at": "2026-06-14T07:10:00Z",
"size_bytes": 12345,
"file_count": 8,
"entry_path": "index.html",
"pin_protected": false,
"visibility": "public"
}Get page details
Returns page metadata: address, site size, file count, entry point, lifetime, PIN protection and visibility.
| Parameter | Description |
|---|---|
| id | Page ID. |
{
"id": "abc123",
"url": "https://mypage.htmlkin.io",
"expires_at": null,
"created_at": "2026-06-14T07:00:00Z",
"updated_at": "2026-06-14T07:10:00Z",
"size_bytes": 12345,
"file_count": 8,
"entry_path": "index.html",
"pin_protected": false,
"visibility": "public"
}Delete a page
Deletes the page permanently. If a custom domain was attached to the page, the domain stays in the account — only its link to this page is removed.
| Parameter | Description |
|---|---|
| id | Page ID. |
{
"id": "abc123",
"deleted": true
}Error codes
The error body is always the same: { "error": "<code>", "message": "<description>" }.
| HTTP | error | Description |
|---|---|---|
| 400 | invalid_file | The single file doesn't look like HTML. |
| 400 | invalid_site | Invalid combination of sources or an invalid set of site files. |
| 400 | invalid_archive | The ZIP is damaged, encrypted or uses an unsupported format. |
| 400 | invalid_path | Invalid, unsafe or duplicate file path. |
| 400 | missing_entry_file | There is no HTML file in the site root. |
| 400 | too_many_files | The site has more than 500 useful files. |
| 400 | banner_removal | A site file contains code that removes the htmlkin promo bar; the bar goes away on a paid plan. |
| 400 | invalid_pin | The PIN is not 4 digits. |
| 400 | invalid_visibility | visibility is not one of public, link, team, private. |
| 400 | invalid_subdomain | The subdomain has invalid characters (allowed: a-z, 0-9, “-”). |
| 401 | invalid_api_key | Invalid or missing API key. |
| 403 | account_banned | The account has been blocked for violating the terms of service. |
| 403 | team_visibility_requires_plan | team is available on the Business plan. |
| 403 | content_blocked | The entry page (index.html) is byte-for-byte identical to a page of a site blocked for violating the terms of service. |
| 403 | dangerous_link | The page links to a URL that Google Web Risk flags as phishing or malware. |
| 403 | page_limit_exceeded | The plan's active site limit has been reached. |
| 404 | not_found | The page was not found or belongs to another owner. |
| 409 | subdomain_taken | The requested subdomain is already taken. |
| 413 | file_too_large | The unpacked site is larger than 200 MB, the limit for a single upload. |
| 413 | storage_limit_exceeded | The site doesn't fit in the storage: together with the account's other active sites it would exceed the plan's storage. On update, the space of the site's current version counts as free. |
| 429 | rate_limit_exceeded | Too many requests; the response has a Retry-After header. |
Testing and client generation
The API is described by a machine-readable OpenAPI 3.1 spec. Import it to send requests interactively and generate a ready-made client for your language:
- Swagger UI / Postman — paste
https://htmlkin.io/api/v1/openapi.json, set the Bearer key and call endpoints right from your browser. - openapi-generator — generate an SDK for Python, TypeScript, Go and other languages with a single command from the same spec.
Publishing from AI assistants (MCP)
The same API is available through the MCP server https://htmlkin.io/mcp — Claude and other assistants publish and update sites right from the chat, with your API key. Nothing to install or run.