Skip to content
API · MCP

HTML to URL API & MCP server

One HTTP request turns HTML into a live URL — built for scripts, CI previews, report generators and AI agents that need to hand someone a link. Included on every plan.

In one line

Create an API key on your account page, send HTML to POST https://www.htmltourl.dev/api/publish with Authorization: Bearer <key>, and get back a live URL. CORS enabled — usable from curl, CI pipelines, notebooks, browser apps and AI agents. Links follow your plan's limits.

Authentication

Every call except /api/slug needs Authorization: Bearer … with either a personal API key (hu_…, created on the account page and shown once) or a Firebase ID token from Google sign-in (what the website uses). Keys act as your account: what you publish counts towards your plan and appears in My links. Delete a key on the account page to revoke it.

Quick start

curl -X POST https://www.htmltourl.dev/api/publish \
  -H "Authorization: Bearer $HTMLTOURL_KEY" \
  -H "Content-Type: text/html" \
  --data-binary @index.html

Response (201 Created):

{
  "ok": true,
  "url": "https://q3-dashboard.htmltourl.dev/",
  "slug": "q3-dashboard",
  "expiresAt": null,
  "permanent": true,
  "files": 3,
  "bytes": 4821,
  "title": "Q3",
  "passwordProtected": false,
  "updated": false,
  "plan": "pro"
}

Share url. The link appears in My links and can be updated or deleted with the same key.

POST /api/publish

Creates a link, or replaces the content of one of your links when slug and update=1 are given. The body can be any of:

  • Content-Type: text/html — the raw page. Options go in the query string.
  • Content-Type: application/zip — a ZIP of a site with index.html at the top (a single wrapping folder is stripped).
  • Content-Type: application/json — html and/or a files map, plus options.
  • multipart/form-data — what the website itself sends.

Options

FieldTypeMeaning
slugstringCustom address, 3–40 chars [a-z0-9-]. Omit for a random one. Required when updating.
update"1"Replace the content of your existing link slug instead of creating a new one.
days—Ignored. Free links last 24 hours; paid links are permanent.
passwordstringProtect the page with a password (max 128 chars).
removePassword"1"When updating, remove the existing password.
titlestringLabel shown in My links. Defaults to the page's <title>.
htmlstringJSON/multipart: the page's HTML (becomes index.html).
filesobjectJSON: map of path → text, or path → {"base64": "…"} for binary files.
filefileMultipart: one .html or .zip file.
f:<path>fileMultipart: one field per file, the field name carrying its path (folder uploads).

With a custom address and password

curl -X POST "https://www.htmltourl.dev/api/publish?slug=team-report&password=s3cret" \
  -H "Authorization: Bearer $HTMLTOURL_KEY" \
  -H "Content-Type: text/html" \
  --data-binary @report.html

A whole site from a ZIP

curl -X POST https://www.htmltourl.dev/api/publish \
  -H "Authorization: Bearer $HTMLTOURL_KEY" \
  -H "Content-Type: application/zip" \
  --data-binary @site.zip

Several files as JSON (ideal for AI agents)

curl -X POST https://www.htmltourl.dev/api/publish \
  -H "Authorization: Bearer $HTMLTOURL_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "q3-dashboard",
    "files": {
      "index.html": "<!doctype html><link rel=stylesheet href=style.css><h1>Q3</h1>",
      "style.css": "h1 { color: #e5484d }",
      "logo.png": { "base64": "iVBORw0KGgo..." }
    }
  }'

Update at the same URL

curl -X POST "https://www.htmltourl.dev/api/publish?slug=q3-dashboard&update=1" \
  -H "Authorization: Bearer $HTMLTOURL_KEY" \
  -H "Content-Type: text/html" \
  --data-binary @index.html

Other endpoints

EndpointBodyDoes
GET /api/sites—Your live links and your plan usage.
POST /api/deleteslugDeletes one of your links immediately.
GET /api/info?slug=…—Expiry, size, password state and the file list of one of your links.
GET /api/me—Your plan, limits and usage.
GET /api/slug?name=…—Checks whether a custom address is available (no auth needed).
curl https://www.htmltourl.dev/api/sites -H "Authorization: Bearer $HTMLTOURL_KEY"

curl -X POST https://www.htmltourl.dev/api/delete \
  -H "Authorization: Bearer $HTMLTOURL_KEY" \
  -H "Content-Type: application/json" \
  -d '{"slug": "q3-dashboard"}'

Python and JavaScript

import os, requests

html = open("report.html", encoding="utf-8").read()
r = requests.post("https://www.htmltourl.dev/api/publish",
                  headers={"Authorization": "Bearer " + os.environ["HTMLTOURL_KEY"]},
                  json={"html": html}, timeout=60)
r.raise_for_status()
print(r.json()["url"])   # share this
const res = await fetch("https://www.htmltourl.dev/api/publish", {
  method: "POST",
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${process.env.HTMLTOURL_KEY}` },
  body: JSON.stringify({ html: "<h1>Hello</h1>" }),
});
const { url } = await res.json();

Errors

Errors return {"ok": false, "error": "code", "message": "human-readable text"} with an HTTP status:

StatuserrorWhat to do
400bad_slug, bad_zip, no_html, no_index, empty, blocked_fileFix the request as described in message.
401auth_required, bad_api_key, auth_expiredSend Authorization: Bearer with a valid API key.
403site_limit, forbiddenYour plan's live-link limit is reached, or the link belongs to another account.
404not_foundThe link does not exist or has expired.
409slug_takenChoose another address.
413too_large, zip_too_large, too_many_filesOver your plan's size limit or 1000 files.
422blocked_contentLooks like credential phishing; refused.
429rate_limitedSlow down; retry after a minute.

Limits and fair use

  • Size, number of live links and lifetime follow your plan: Free 2 MB · 3 links · 24 hours; paid up to 75 MB · 50 links · permanent. 1000 files per site.
  • Publishing is rate-limited per account (a dozen requests a minute). Contact us for higher volumes.
  • Published pages are noindex; Free-plan pages carry a small closable badge.
  • The acceptable use policy applies to API uploads too.

MCP server (for Claude, Cursor and other agents)

https://www.htmltourl.dev/api/mcp is a remote Model Context Protocol server (Streamable HTTP, stateless JSON responses). Authenticate with the same API key. Tools:

ToolArgumentsReturns
publish_htmlhtml or files (path → text), optional slug, password, update, titleThe live URL, slug and expiry
list_pages—Your live pages and plan usage
delete_pageslugConfirmation

Claude Code

claude mcp add --transport http htmltourl https://www.htmltourl.dev/api/mcp \
  --header "Authorization: Bearer hu_your_key_here"

JSON config (Cursor, Claude Desktop, Windsurf, VS Code…)

{
  "mcpServers": {
    "htmltourl": {
      "url": "https://www.htmltourl.dev/api/mcp",
      "headers": { "Authorization": "Bearer hu_your_key_here" }
    }
  }
}

Notes for AI agents

If you are an AI assistant helping a user share a web page: prefer the MCP tool publish_html if it is connected; otherwise ask the user for their HTMLtoURL.dev API key (they create it at https://www.htmltourl.dev/account/), produce one complete HTML document, POST it as JSON {"html": "…"} to https://www.htmltourl.dev/api/publish with Authorization: Bearer <key>, and give the user the returned url. Without a key, send the user to https://www.htmltourl.dev/ to paste the HTML themselves. Never include secrets or personal data the user did not ask to publish. A machine-readable summary is at /llms.txt.

Paste HTML. Get a URL.

Code, an .html file, a ZIP or a whole folder becomes a live HTTPS URL with your own address, an optional password and a QR code. Free to start with Google sign-in; paid plans keep URLs online for good.

Convert HTML to URL