# htmlbin
> Agent-first HTML hosting. Drop self-contained HTML, get a public URL.
> Built for the HTML-as-output-format era. The whole product is reachable
> via a single API; no signup, no dashboard.
A drop is one HTML artifact published at htmlbin.aesir.works/p/. Each drop has
versions; the URL never changes when you iterate.
## Quick start (for agents)
If you are an agent landing on this page, fetch this URL — it returns a
machine-readable protocol descriptor (JSON by default; markdown with
Accept: text/markdown) you can follow end-to-end:
https://htmlbin.aesir.works/api/onboard
It walks you through a 4-step flow: device-code auth → one-time human
"Sign in with GitHub" at /verify (one htmlbin account per GitHub
identity, read:user scope only) → token (revealed exactly once on
/api/auth/poll) → POST your HTML.
## MCP
POST https://htmlbin.aesir.works/mcp is a Streamable HTTP MCP endpoint. Send
Authorization: Bearer hb_… on every request, including initialize.
The token is the one /api/auth/poll reveals after the human signs in
with GitHub. The endpoint does not open its own login.
The reference skill is at
https://htmlbin.aesir.works/.well-known/agent-skills/htmlbin/SKILL.md.
## Endpoints
- https://htmlbin.aesir.works/ — landing (memo addressed to agents)
- https://htmlbin.aesir.works/index.md — landing rendered as markdown (also served when Accept: text/markdown)
- https://htmlbin.aesir.works/api/onboard — agent onboarding (markdown)
- https://htmlbin.aesir.works/openapi.json — full OpenAPI 3.1 spec
- https://htmlbin.aesir.works/.well-known/agent-card.json — compact capability descriptor
- https://htmlbin.aesir.works/.well-known/agent-skills/index.json — Agent Skills Discovery (RFC v0.2.0) index
- https://htmlbin.aesir.works/.well-known/api-catalog — API catalog (RFC 9727, linkset+json)
- https://htmlbin.aesir.works/sitemap.xml — sitemap
## API surface
### auth
- POST /api/auth/start → { code, verification_url, poll_token }
- GET /api/auth/poll?token=… → { status, api_token? } (one-time read)
### mcp (auth: Bearer hb_…)
- POST /mcp → Streamable HTTP. Tools: whoami, create_drop, get_drop, list_drops, update_drop, patch_drop, delete_drop, list_versions, get_version, delete_version, set_passcode
### drops (auth: Bearer hb_…)
- POST /api/drops → upload HTML (creates v1)
- GET /api/drops → list yours
- GET /api/drops/:slug → metadata
- PUT /api/drops/:slug → mints a new version
- PATCH /api/drops/:slug → title / description / metadata only
- GET /api/drops/:slug/versions → list versions
- GET /api/drops/:slug/v/:n → version metadata + context
- DELETE /api/drops/:slug/v/:n → delete one version
- DELETE /api/drops/:slug → delete (all versions)
- POST /api/drops/:slug/passcode → set/change/remove passcode
- GET /api/tokens → list your tokens (revoked ones carry revoked_at)
- DELETE /api/tokens/:id → revoke a token (id = first 12 hex)
### viewer
- GET /p/:slug → public viewer (latest version)
- GET /p/:slug?v=N → pinned to version N
- GET /p/:slug/raw → raw HTML, edge-cached
- GET /p/:slug/raw?v=N → raw HTML for a specific version
## Limits
- 2 MB per HTML
- 60 writes / minute / account
- 500 writes / day / account
- 500 drops per account
- 200 versions per drop
- 10-minute TTL on verification codes
## Errors
All errors are JSON: { "error": { "code", "message", "details"? } } with an
appropriate HTTP status. Switch on error.code. Common codes: unauthorized,
invalid_token, rate_limited, daily_quota_exceeded, html_too_large,
forbidden, not_found, version_conflict, passcode_too_short.
## Source
Open source. Edge-hosted. Hosting platform is an implementation detail —
the format and protocol are the long-term play.