API reference · v1

The HTML Docs collaboration API

A REST API for creating, editing, commenting on, and versioning documents — built so an agent and a human can work the same page at the same time. Everything below is callable with one curl.

Quickstart Use it in Claude Codehttps://www.html-docs.com/api/v1

Getting started

Introduction#

What the API does and how documents are shaped.

HTML Docs turns static HTML into a collaborative document. On import the page is split into regions — the block-level elements (paragraphs, headings, list items, table cells) — and each region becomes independently editable. The API is how an agent reads those regions, edits them, comments on them, and tracks every change.

All endpoints live under https://www.html-docs.com/api/v1. Requests and responses are JSON unless noted; document content is HTML or Markdown. The maximum request body is 2 MB.

The reference below is mirrored from the running code. The always-current machine-readable contract is GET /api/v1.

Getting started

Authentication#

Two ways to authorize a request — an account key, or a per-document token.

Agent API keys are account-level. A key acts as its owner and can reach every document that account owns or collaborates on. Send it as a bearer token (or the x-api-key header). Mint and revoke keys at /settings/api-keys. Keys are shown once and start with hdk_.

Authorize with an agent key
curl https://www.html-docs.com/api/v1/docs/<id> \
  -H 'Authorization: Bearer hdk_live_xxx'

Document tokens are per-document share tokens — the kind returned by POST /docs. A token authorizes one document. It always grants read access; it grants write access on anonymous documents, and on human-owned documents only when the owner has enabled link editing.

Authorize with a doc token
curl https://www.html-docs.com/api/v1/docs/<id> \
  -H 'x-doc-token: <token>'

# or as a query param
curl 'https://www.html-docs.com/api/v1/docs/<id>?token=<token>'
Add an optional x-agent-name header (e.g. Claude Code) to label the comments and versions your agent creates. They are attributed to that name and rendered distinctly from human contributions in the editor.

Getting started

Errors#

Conventional HTTP status codes. Every error body is { error: string }.

Status codes

200 / 201 / 204
success

OK · Created · No Content (a successful delete).

400
bad request

Malformed JSON, a missing required field, or an invalid parent_id.

401
unauthorized

No credentials were supplied at all.

403
forbidden

Invalid/revoked key, wrong doc token, a read-only document, or editing a human-authored comment.

404
not found

Unknown — or unreachable — document, region, comment, or version. Existence is not leaked.

413
too large

The request body exceeded the 2 MB limit.

429
rate limited

Too many requests in the window. Honor the Retry-After header.

500
server error

Something failed server-side. Safe to retry with backoff.

Error response
{
  "error": "Invalid token for this document."
}

Getting started

Rate limits#

A fixed 60-second window, counted per credential.

Each credential — an agent key or a doc token — gets 600 reads and 60 writes per rolling 60-second window. Over the limit, the API responds 429 with a Retry-After header in seconds — wait that long and retry.

Rate-limited response
HTTP/1.1 429 Too Many Requests
Retry-After: 42

{ "error": "Rate limit exceeded. Slow down and retry." }

Getting started

Quickstart#

Create a doc, read it, edit a region, leave a comment — start to finish.

Terminal
# 1 — publish a page (no auth — hosted at /site/<slug>)
curl -sS -X POST https://www.html-docs.com/api/v1/docs \
  -H 'Content-Type: text/html' --data-binary @page.html
# → { "url": "https://www.html-docs.com/site/page-a7k2b9f1", "slug": "page-a7k2b9f1",
#     "editUrl": "https://www.html-docs.com/s/ab12cd34?present=1", "token": "ab12cd34" }

# 1b — or publish with an agent key + custom slug (permanent, owned)
curl -sS -X POST 'https://www.html-docs.com/api/v1/docs?slug=my-dashboard' \
  -H 'Authorization: Bearer hdk_live_xxx' \
  -H 'Content-Type: text/html' --data-binary @dashboard.html
# → { "url": "https://www.html-docs.com/site/my-dashboard", "slug": "my-dashboard", "owned": true }

# 2 — read it back: title, html_content, and editable regions
curl -sS https://www.html-docs.com/api/v1/docs/d3f… -H 'x-doc-token: ab12cd34'

# 3 — edit one region in place (comment anchors survive)
curl -sS -X PATCH https://www.html-docs.com/api/v1/docs/d3f…/regions/region-7a1c \
  -H 'x-doc-token: ab12cd34' -H 'Content-Type: application/json' \
  -d '{"content":"<p>The revised opening paragraph.</p>"}'

# 4 — leave a comment anchored to a span of text
curl -sS -X POST https://www.html-docs.com/api/v1/docs/d3f…/comments \
  -H 'x-doc-token: ab12cd34' -H 'Content-Type: application/json' \
  -d '{"content":"Tighten this claim.","region_key":"region-7a1c","selected_text":"revised opening"}'

That is the whole loop. No SDK, no install — every other endpoint is a variation on these four calls.

Core resources

Documents#

Create a document, read its content and regions, or replace it wholesale.

POST/api/v1/docs

Turn an HTML or Markdown payload into a shareable document with a live URL in one call. Two auth modes:

  • No auth — anonymous, unlisted. The response tokenis the doc's share token; keep it for later updates.
  • Agent key (Authorization: Bearer hdk_…) — permanent, private, owned by your account. Shows in your dashboard.

Send the body as raw text/html / text/markdown, or as JSON { html | markdown, title }.

Inline scripts are preserved. Agents publishing dashboards, charts (Chart.js, D3, Plotly), SPAs, and interactive sites get their <script> tags through untouched. This is the instant-hosting path — publish once, get a live URL with working JavaScript.

Body

html / markdown
stringrequired

The document source. Raw body, or a JSON field. One or the other.

title
string

Optional title. Also accepted as a ?title= query param. Inferred from the HTML when omitted.

slug
string

Optional custom slug for the hosted URL. Pass as ?slug= query param or X-Slug header. Auto-generated when omitted.

Response fields

id
string

Document UUID.

url
string

Hosted page URL at /site/<slug> — raw HTML, no editor chrome.

slug
string

The published slug. Use for updates or custom URLs.

editUrl
string

Editor URL (/s/<code>) for converting to a collaborative doc.

token
string

Share token for later reads and edits via the API.

owned
boolean

Present and true when created with an agent key.

visibility
string

Present on owned docs. "private" by default.

Anonymous (zero friction)

Request
# Anonymous — zero friction, auto-published at /site/<slug>
curl -sS -X POST https://www.html-docs.com/api/v1/docs \
  -H 'Content-Type: text/html' \
  -H 'x-agent-name: Claude Code' \
  --data-binary @page.html
201 Response
{
  "id": "d3f8a1c2-…",
  "url": "https://www.html-docs.com/site/page-a7k2b9f1",
  "slug": "page-a7k2b9f1",
  "editUrl": "https://www.html-docs.com/s/ab12cd34?present=1",
  "token": "ab12cd34"
}

Authenticated (permanent, owned)

Request
# Authenticated — permanent, owned, slug derived from title
curl -sS -X POST https://www.html-docs.com/api/v1/docs \
  -H 'Authorization: Bearer hdk_live_xxx' \
  -H 'Content-Type: text/html' \
  -H 'x-agent-name: Claude Code' \
  --data-binary @dashboard.html
201 Response
{
  "id": "e7a4b2d1-…",
  "url": "https://www.html-docs.com/site/launch-plan-c8d2",
  "slug": "launch-plan-c8d2",
  "editUrl": "https://www.html-docs.com/s/cd56ef78?present=1",
  "token": "cd56ef78",
  "owned": true,
  "visibility": "private"
}

Custom slug

Request
# Custom slug — choose your own URL
curl -sS -X POST 'https://www.html-docs.com/api/v1/docs?slug=my-dashboard' \
  -H 'Authorization: Bearer hdk_live_xxx' \
  -H 'Content-Type: text/html' \
  --data-binary @dashboard.html

# or via header:
curl -sS -X POST https://www.html-docs.com/api/v1/docs \
  -H 'Authorization: Bearer hdk_live_xxx' \
  -H 'X-Slug: my-dashboard' \
  -H 'Content-Type: text/html' \
  --data-binary @dashboard.html
GET/api/v1/docs/:id

Read a document: its title, metadata, full html_content (the shell, with {{region-key}} placeholders), and the regions array — each an independently editable block.

Request
curl -sS https://www.html-docs.com/api/v1/docs/d3f8a1c2-… \
  -H 'x-doc-token: ab12cd34'
200 Response
{
  "id": "d3f8a1c2-…",
  "title": "Launch plan",
  "visibility": "unlisted",
  "share_can_edit": false,
  "html_content": "<!doctype html>… {{region-7a1c}} …",
  "regions": [
    { "region_key": "region-7a1c", "content": "<p>The opening paragraph.</p>" },
    { "region_key": "region-b920", "content": "<h2>Milestones</h2>" }
  ],
  "updated_at": "2026-05-18T19:04:22.118Z"
}
PUT/api/v1/docs/:id

Replace a document's content wholesale (PATCH is an alias). The prior state is snapshotted to version history first, so a PUT is always restorable.

Heads up: a PUT re-derives every region key, so comments anchored to the old content are orphaned. For a targeted change, prefer PATCH /regions/:key — it preserves anchors.
Request
curl -sS -X PUT https://www.html-docs.com/api/v1/docs/d3f8a1c2-… \
  -H 'x-doc-token: ab12cd34' \
  -H 'Content-Type: text/markdown' \
  --data-binary @rewrite.md

Core resources

Regions#

Read or edit a single block in place — the anchor-preserving edit path.

GET/api/v1/docs/:id/regions/:regionKey

Read one region's current HTML content.

Request
curl -sS https://www.html-docs.com/api/v1/docs/d3f8a1c2-…/regions/region-7a1c \
  -H 'x-doc-token: ab12cd34'
PATCH/api/v1/docs/:id/regions/:regionKey

Replace one region's content. Only the named region changes — every other region, and the comments anchored to it, are left intact. This is the precise edit path an agent should reach for. Editing a human-owned document checkpoints a version first. An unknown region key returns 404 — regions are never created this way.

Body

content
stringrequired

The replacement HTML. JSON { "content": "…" }, or a raw text/html body.

Request
curl -sS -X PATCH https://www.html-docs.com/api/v1/docs/d3f8a1c2-…/regions/region-7a1c \
  -H 'x-doc-token: ab12cd34' \
  -H 'Content-Type: application/json' \
  -d '{"content":"<p>The revised opening paragraph.</p>"}'
200 Response
{
  "region_key": "region-7a1c",
  "content": "<p>The revised opening paragraph.</p>"
}

Core resources

Comments#

Threaded, text-anchored comments — the channel between an agent and a human reviewer.

GET/api/v1/docs/:id/comments

List comment threads — root comments with nested replies.

Query parameters

resolved
true | false | all

Filter by resolved state. Defaults to all.

region_key
string

Restrict to comments anchored to one region.

Request
curl -sS 'https://www.html-docs.com/api/v1/docs/d3f8a1c2-…/comments?resolved=false' \
  -H 'x-doc-token: ab12cd34'
200 Response
{
  "comments": [
    {
      "id": "c1a2…",
      "author_type": "human",
      "author_name": "Priya",
      "region_key": "region-7a1c",
      "selected_text": "revised opening",
      "content": "Can we lead with the metric instead?",
      "resolved": false,
      "replies": [
        { "id": "c9f0…", "author_type": "agent", "author_name": "Claude Code",
          "content": "Done — moved the 4x figure into the first line." }
      ]
    }
  ]
}
POST/api/v1/docs/:id/comments

Add a comment. A comment with a selected_text snippet shows a highlight on the page; one with only a region_key is invisible to the reader — so always pass a short, exact, plain-text snippet. Created comments are attributed author_type: "agent".

Body

content
stringrequired

The comment text.

region_key
string

Anchor the comment to a region. Must exist on the document.

selected_text
string

A short, exact, verbatim plain-text snippet to highlight within the region.

parent_id
string

Post as a reply within an existing thread on this document.

anchor_offset
number

Disambiguate when selected_text repeats in the region. Usually omitted.

Request
curl -sS -X POST https://www.html-docs.com/api/v1/docs/d3f8a1c2-…/comments \
  -H 'x-doc-token: ab12cd34' \
  -H 'Content-Type: application/json' \
  -d '{
    "content": "This number needs a source.",
    "region_key": "region-b920",
    "selected_text": "3.8x faster"
  }'
201 Response
{
  "comment": {
    "id": "c1a2b3c4-…",
    "author_type": "agent",
    "author_name": "Claude Code",
    "region_key": "region-b920",
    "selected_text": "3.8x faster",
    "content": "This number needs a source.",
    "resolved": false,
    "replies": []
  }
}
PATCH/api/v1/docs/:id/comments/:commentId
DELETE/api/v1/docs/:id/comments/:commentId

Edit ({ content }) or delete a comment. An agent may only modify comments authored by an agent — editing or deleting a human's comment returns 403. A delete returns 204.

POST/api/v1/docs/:id/comments/:commentId/resolve

Resolve or unresolve a thread with { "resolved": true | false } (omit the body to resolve). Resolving is thread management, not editing — it works on any comment, human- or agent-authored, and is idempotent.

Request
curl -sS -X POST \
  https://www.html-docs.com/api/v1/docs/d3f8a1c2-…/comments/c1a2b3c4-…/resolve \
  -H 'x-doc-token: ab12cd34' \
  -H 'Content-Type: application/json' \
  -d '{"resolved":true}'

Core resources

Versions#

Every API write snapshots the prior state. List, capture, and restore.

GET/api/v1/docs/:id/versions

List versions, newest first. The heavy snapshot blob is omitted unless ?include=snapshot is set.

200 Response
{
  "versions": [
    {
      "id": "v7c2…",
      "version_number": 4,
      "name": "Draft sent to client",
      "author_type": "agent",
      "agent_name": "Claude Code",
      "created_by_name": null,
      "created_at": "2026-05-18T19:10:00.000Z",
      "region_count": 22
    }
  ]
}
POST/api/v1/docs/:id/versions

Capture a version of the current state. Pass an optional { "name": "…" }. A capture with no change since the latest version is deduped.

Request
curl -sS -X POST https://www.html-docs.com/api/v1/docs/d3f8a1c2-…/versions \
  -H 'x-doc-token: ab12cd34' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Draft sent to client"}'
POST/api/v1/docs/:id/versions/:versionId/restore

Roll the document back to a version. The current state is captured as a new version first, so the restore is itself undoable.

Core resources

Activity#

A pull-based feed of everything happening on a document.

GET/api/v1/docs/:id/activity

Recent events — comments created/edited/deleted/resolved, versions captured, content edits — newest first, covering human and agent activity alike. Poll it with ?since= for a cheap way to react to changes without a webhook.

Query parameters

since
ISO timestamp

Only events strictly after this time.

type
csv

Restrict to event types, e.g. comment.created,version.created.

limit
number

Page size. Default 50, max 200.

Request
curl -sS 'https://www.html-docs.com/api/v1/docs/d3f8a1c2-…/activity?since=2026-05-18T19:00:00Z&type=comment.created' \
  -H 'x-doc-token: ab12cd34'
200 Response
{
  "events": [
    {
      "type": "comment.created",
      "actor_type": "human",
      "actor_name": "Priya",
      "region_key": "region-7a1c",
      "created_at": "2026-05-18T19:06:41.220Z"
    }
  ]
}

Core resources

Webhooks#

The push-based counterpart to the activity feed.

Register a callback URL and HTML Docs will POST a JSON payload to it on each event. Account webhooks (POST /api/v1/webhooks) need an agent key; omit document_id to watch every document you own. Per-document webhooks (POST /api/v1/docs/:id/webhooks) also accept a doc token, so a token-only caller can subscribe to its one document.

Event types

comment.created
event

A new comment or reply was added.

comment.updated
event

A comment’s content was edited.

comment.deleted
event

A comment was deleted.

comment.resolved / .unresolved
event

A thread was resolved or reopened.

version.created
event

A version was captured.

document.updated
event

Document or region content changed.

POST/api/v1/webhooks

Body

url
stringrequired

A public HTTPS callback URL.

document_id
string

Scope to one document. Omit to watch every document you own.

event_types
string[]

Subscribe to specific events. Omit for all of them.

description
string

An optional label for your own bookkeeping.

Request
curl -sS -X POST https://www.html-docs.com/api/v1/webhooks \
  -H 'Authorization: Bearer hdk_live_xxx' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://your-host.dev/htmldocs-hook",
    "event_types": ["comment.created"],
    "description": "Ping me on new comments"
  }'
201 Response
{
  "id": "wh_8a1c…",
  "url": "https://your-host.dev/htmldocs-hook",
  "document_id": null,
  "event_types": ["comment.created"],
  "scope": "account",
  "signing_secret": "whsec_… (shown once — store it now)",
  "note": "Store signing_secret now — it is not shown again."
}

The response carries signing_secret once. Verify every delivery with an HMAC-SHA256 of the raw request body keyed by that secret, and compare it against the X-HtmlDocs-Signature header. GET /api/v1/webhooks lists your hooks; DELETE /api/v1/webhooks/:id revokes one.

Verify a delivery — TypeScript
import crypto from 'node:crypto'

// Verify an incoming webhook delivery.
function isValid(rawBody: string, signature: string, secret: string) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature),
  )
}
// signature arrives in the X-HtmlDocs-Signature header

Recipes

Using it in Claude Code#

The API was designed for a coding agent. Here is what that unlocks.

Install the one-file HTML Docs skill and Claude Code can drive every endpoint above with curl — or use the MCP server for native tool integration. It creates a doc, hands you the link, and then keeps editing it while you comment. The four patterns below are the ones that pay off the fastest.

Install the skill
mkdir -p ~/.claude/skills/html-docs \
  && curl -fsSL https://www.html-docs.com/agents/skill.md -o ~/.claude/skills/html-docs/SKILL.md

Instant web hosting for agents

Publish any HTML — a dashboard, a chart, an interactive app — and get a live URL in seconds. Inline scripts survive, so Chart.js, D3, Plotly, and SPAs all work. One curl, one URL, done.

Prompt for Claude Code
Build an interactive dashboard showing <TOPIC> with Chart.js charts and publish it to HTML Docs. Use the API: curl -X POST https://www.html-docs.com/api/v1/docs -H 'Content-Type: text/html' --data-binary @dashboard.html. Give me the live URL.

A living implementation log

The agent keeps a notes doc current as it codes — design decisions, deviations, open questions — so you can follow along and comment in real time instead of reading a wall of diffs at the end.

Prompt for Claude Code
Implement <SPEC>. Create one HTML Docs page as a running implementation log and PATCH its regions as you go — capture design decisions, deviations from the spec, tradeoffs, and open questions. Give me the link now so I can comment while you work.

A design-review loop

The agent publishes a page, you mark it up with comments, and it pulls your comments back through GET /comments and revises the affected regions — then resolves each thread it addressed.

Prompt for Claude Code
Design a landing page for <PRODUCT> and publish it to HTML Docs. Then poll the comments on that doc; when I leave feedback, revise the relevant regions, reply to each comment with what changed, and resolve it.

Review a doc someone sent you

Hand the agent any HTML Docs link. It reads every region and leaves specific, text-anchored comments — the same workflow a human reviewer uses.

Prompt for Claude Code
Review this HTML Docs page critically: <LINK>. Leave a comment on each issue you find, anchored to the exact text, and use the name "Reviewer Agent".

React to changes as they happen

Register a webhook (or poll the activity feed with ?since=) so the agent wakes only when a human comments — then answers or revises without you re-prompting it.

Prompt for Claude Code
Register a webhook on this doc for comment.created events pointing at <YOUR_ENDPOINT>. When a human comment comes in, address it and resolve the thread.
Why it works: region PATCHes keep comment anchors stable across a long editing session, every write is snapshotted so nothing is lost, and the comment thread gives the agent a structured channel to receive your feedback. The agent edits; you review in place; it revises from your comments. That is the loop.

Recipes

MCP Server#

Use HTML Docs as a native tool in any MCP-compatible client.

The @html-docs/cli package includes a built-in Model Context Protocol server. MCP gives your agent native tools for publishing, reading, editing, and commenting — no curl commands, no skill file required.

Add to your MCP config (~/.claude/mcp.json, .cursor/mcp.json, etc.)
{
  "mcpServers": {
    "html-docs": {
      "command": "npx",
      "args": ["@html-docs/cli", "--mcp"]
    }
  }
}

Available tools

ToolDescriptionRequired params
publishPublish HTML content to a live URLhtml
publish_filePublish a local HTML filepath
updateUpdate an existing documentid, html
readRead document content and regionsid
commentAdd a comment anchored to textid, content, region_key, selected_text
list_commentsList all comments on a documentid

All tools also accept optional api_key, token, slug, and title params where applicable. Auth falls back to the HTMLDOCS_API_KEY env var or ~/.htmldocs/credentials (saved via npx @html-docs/cli auth).

Three ways to integrate: MCP for native tool support in Claude Code, Cursor, Windsurf, and Cline. Skill file for agents that read instructions and use curl. Direct API for anything that can make HTTP requests. Same API underneath — pick whatever fits your agent.

One curl away from a collaborative doc.

Start with the quickstart, or hand the skill to your agent and let it make the first one.