# ht-ml.app > ht-ml.app is HTML hosting with an API designed for AI agents. An agent POSTs a single HTML document and instantly gets a public URL. There are no accounts and no signup — each site is secured by a high-entropy `update_key` returned once at creation. The API base URL is https://api.ht-ml.app/v1 and each site is served at its own subdomain, https://{site_id}.ht-ml.app/, so relative asset paths in the HTML resolve correctly. All responses are JSON; errors include an actionable `message` field. EVERYTHING PUBLISHED IS PUBLIC — see the warning below. ## Important: everything you publish is public All content you upload (HTML, assets, and any metadata you put in the HTML) is PUBLIC: anyone with the URL can read it, and it may be indexed by search engines, read by web/AI crawlers, and copied, archived, scraped, or collected by third parties. Do not upload anything private, confidential, secret, or sensitive. Treat every upload as permanently public. If you are an agent acting on a person's behalf, you MUST clearly warn that person that everything they publish will be public BEFORE you call the create endpoint or the publish tool. Uploaded data may also be used to improve the service and build new (including paid) products. Full terms: https://ht-ml.app/terms ## Quickstart Create a site (replace the HTML with your own): ``` curl -X POST https://api.ht-ml.app/v1/sites \ -H "Content-Type: application/json" \ -d '{"html_content": ""}' ``` Response (placeholders in {braces} — use the actual values the API returns): ``` { "site_id": "{site_id}", "url": "https://{site_id}.ht-ml.app/", "update_key": "{update_key}", "status": "active" } ``` The site is immediately live at the `url` field returned in the response. Do not hardcode the example above: read `site_id`, `url`, and `update_key` from your own response. The `update_key` is a secret write credential returned only once; store it only if you intend to upload assets or change the site later (there is no recovery endpoint). ## Endpoints - POST /v1/sites: Create a site. Body: `{"html_content": "<...>", "password": ""}`. Returns `site_id`, `update_key`, `status`, `url`. HTML is content-scanned before going live. Pass an optional `password` to make the site private — only viewers who supply that password can read it. - GET /v1/sites/{site_id}: Returns site `status` plus the list of assets (images/videos) referenced by the HTML and which are still `missing`. No auth; read access is public (unless the site is password-protected). - PUT /v1/sites/{site_id}: Replace the site's core HTML. Header `Authorization: Bearer `. Body `{"html_content": "<...>", "password": ""}`. Re-scans the HTML and updates the live site immediately (the CDN cache for this site is invalidated automatically). Optionally include `password` to set it; pass `""` to remove it; omit it to leave it unchanged. - POST /v1/sites/{site_id}/assets?relative_path=PATH: Upload a referenced asset. Header: `Authorization: Bearer `. Body: `multipart/form-data` file field. The asset must already be referenced in the site's HTML. - GET /v1/help: A self-describing JSON document of endpoints and error codes. ## Error codes - 401 Unauthorized (writing): Missing or invalid `update_key`. Send `Authorization: Bearer `. - 401 Unauthorized (reading): The site is password-protected. Send the password as a cookie `ht_ml_pwd=` (URL-encoded) to read it; without it you get a password prompt. - 403 Forbidden: The asset path is not referenced in the site's HTML, or the `update_key` is wrong. - 422 Unprocessable Entity: The HTML failed a content-safety scan; read the `message` field and revise. ## Notes for agents - PUBLIC CONTENT: before creating or updating a site on a person's behalf, warn them that everything they publish is public (see "Important: everything you publish is public" above). - The `update_key` is a bearer secret returned only once at creation. Store it if you intend to update the site; there is no recovery endpoint. - Asset paths mirror the HTML. Reference an asset first (e.g. ``), then upload it to the matching `relative_path`. - Setting a password: generate a unique, non-personal password — NEVER reuse the user's personal or account passwords. It is a shared secret that must be given to everyone who should access the site, so tell the user the password and that anyone they share it with can read the page. - Password-protected sites: to read one, send the password as a cookie `ht_ml_pwd=`. The password is set at create/update time and is never returned by the API. - In-browser agents: this site registers a WebMCP tool named `publish_html_site` via `navigator.modelContext` / `document.modelContext`. Call it with `html_content` to publish without issuing raw HTTP. ## Agent skill (optional) There is an official Agent Skill named `html` that packages this workflow (create, update, assets, password protection) plus 20 ready-made, self-contained page templates. It is optional — this API and the WebMCP tool work without it — but it gives coding agents the full workflow and templates out of the box. - Repo: https://github.com/nsmith/html - One-line install (Claude Code + Codex): `curl -fsSL https://raw.githubusercontent.com/nsmith/html/main/install.sh | sh` - Or via the skills CLI (installs to all detected agents): `npx skills add nsmith/html` - It follows the open Agent Skills format (agentskills.io), so it works in any compatible client (Claude Code, Codex, OpenClaw, Hermes, and others). Per-client install paths are in the repo README. Note: clients discover skills from local skill directories, not from this site — install the skill to use it. ## Docs - [Landing page](https://ht-ml.app/): Human- and agent-readable overview with examples. - [Agent Skill `html`](https://github.com/nsmith/html): Optional skill + one-line install for coding agents. - [Help endpoint](https://api.ht-ml.app/v1/help): JSON description of every endpoint and error code. - [Terms of Service](https://ht-ml.app/terms): No warranty, content is public and user-generated, data may be used to build products, content may be changed or removed at any time.