{"schema_version":"1.0","name":"htmlbin","description":"Agent-first HTML hosting. Drop self-contained HTML, get a public URL.","home":"https://htmlbin.dev","contact":"https://htmlbin.dev/","onboarding":{"url":"https://htmlbin.dev/api/onboard","content_types":["text/markdown","application/json"],"summary":"Single endpoint that returns the full agent protocol as markdown."},"auth":{"type":"device_code","start":"https://htmlbin.dev/api/auth/start","poll":"https://htmlbin.dev/api/auth/poll","verify_human_at":"https://htmlbin.dev/verify","token_format":"Bearer hb_<base62>","token_lifetime":"non-expiring (revocable)"},"cli":{"package":"@htmlbin/cli","install":"npm i -g @htmlbin/cli","runtime":"Node 20+","summary":"First-party CLI wrapping every capability below. Auto-emits JSON when invoked from a coding-agent runner. Stable exit codes; the bracketed `error.code` on stderr mirrors this API's error.code shape.","cloud_only_flags":["--metadata","--upsert"]},"skill":{"name":"htmlbin-publish","distribution":"skills.sh","install":"npx skills add https://github.com/utsengar/htmlbin-cli --skill htmlbin-publish","source":"https://github.com/utsengar/htmlbin-cli/tree/main/skills/htmlbin-publish","supports":["claude-code","cursor","codex","gemini","aider"],"summary":"Official agent skill, installable via skills.sh. Smaller and more opinionated than the comprehensive reference at /.well-known/agent-skills/htmlbin/SKILL.md — walks the agent through the pattern-before-publish workflow so each drop is shaped by an explicit pattern.","see_also":"https://htmlbin.dev/.well-known/agent-skills/htmlbin/SKILL.md"},"capabilities":[{"id":"publish_html","description":"Upload self-contained HTML up to 2 MB; receive a permanent public URL. Creates v1. Returns the full Drop with status 201. Optional `metadata` (string→string, ≤10 keys) attaches owner-side tags for later lookup.","method":"POST","path":"/api/drops","accepts":["title","description?","html","passcode?","context?","metadata?"],"cli":{"command":"htmlbin publish <file>","flags":["--title <text>","--description <text>","--metadata <k=v> (cloud only; repeatable, up to 10)","--upsert (cloud only; lookup-by-metadata first → PUT if matched, POST otherwise; requires --metadata)"]}},{"id":"update_html","description":"PUT mints a NEW version on the same slug — URL is preserved across iterations. `html` is required; title/description/metadata optional. Metadata replace semantics: omit → untouched, {} → cleared.","method":"PUT","path":"/api/drops/:slug","accepts":["html","title?","description?","context?","metadata?"],"cli":{"command":"htmlbin update <slug> --file <path>","note":"Presence of --file is what selects PUT in the unified `htmlbin update <slug>` subcommand (omit it for PATCH).","flags":["--file <path> (required for PUT — supplies the new HTML body)","--title <text>","--description <text>","--metadata <k=v> (replaces the whole metadata map; repeatable)","--clear-metadata (sends metadata: {}; mutually exclusive with --metadata)"]}},{"id":"update_metadata","description":"PATCH updates title, description, and/or metadata without minting a new version. Returns 400 metadata_only_on_patch if `html` is included. Metadata replace semantics: omit → untouched, {} → cleared.","method":"PATCH","path":"/api/drops/:slug","accepts":["title?","description?","metadata?"],"cli":{"command":"htmlbin update <slug>","note":"Without --file, the unified `htmlbin update <slug>` subcommand dispatches PATCH (metadata-only).","flags":["--title <text>","--description <text>","--metadata <k=v> (replaces the whole metadata map; repeatable)","--clear-metadata (sends metadata: {}; mutually exclusive with --metadata)"]}},{"id":"list_versions","method":"GET","path":"/api/drops/:slug/versions"},{"id":"get_version","description":"Includes the optional context recorded at that version.","method":"GET","path":"/api/drops/:slug/v/:n"},{"id":"delete_drop","description":"Returns 204 No Content.","method":"DELETE","path":"/api/drops/:slug"},{"id":"delete_version","description":"Delete a single version. Refused for the last remaining version; if the deleted version was the head, latest_version is recomputed. Returns the updated Drop.","method":"DELETE","path":"/api/drops/:slug/v/:n"},{"id":"list_my_drops","description":"Paginated list. Query params: page (default 1), pageSize (default 50, max 200), sortBy (created_at|updated_at|view_count), sortOrder (asc|desc). Also supports repeated `metadata.<key>=<value>` params for AND-filtering — the canonical lookup-then-mutate primitive for finding a drop you previously tagged (any tag combination — PR previews, session artifacts, client portfolios, document kinds, etc).","method":"GET","path":"/api/drops","cli":{"command":"htmlbin list","flags":["--metadata <k=v> (cloud only; repeatable, AND across pairs)","--limit <n> / -n <n>"]}},{"id":"lock_with_passcode","description":"Set, change, or remove a passcode (soft share gate, not encryption). Pass empty string to remove. Returns the updated Drop.","method":"POST","path":"/api/drops/:slug/passcode"},{"id":"whoami","description":"Returns user_id, created_at, drop_count, and current token info (id, label, created_at, last_used_at).","method":"GET","path":"/api/me"},{"id":"list_my_tokens","description":"List active tokens for this user across machines (read-only, no plaintext).","method":"GET","path":"/api/tokens"},{"id":"revoke_token","description":"Revoke a specific token by its short id (first 12 hex chars of the hash). Returns 204 No Content.","method":"DELETE","path":"/api/tokens/:id"}],"error_shape":{"shape":"{ error: { code, message, details? } }","switch_on":"error.code","note":"All 4xx/5xx responses use this shape. Rate-limited responses (429) additionally carry a Retry-After header."},"naming_convention":"snake_case","cors":{"posture":"deny","note":"No CORS headers are set. Browser cross-origin XHR will fail by design. htmlbin is an agent-side API; call it from CLI / server-side / agent runtimes, not from arbitrary third-party web pages."},"versioning":{"semantics":"Every PUT with a new html body increments the version. Slug + URL stay stable.","view_specific_version":"/p/<slug>?v=<n>","raw_specific_version":"/p/<slug>/raw?v=<n>"},"cross_machine_auth":{"method":"Run /api/auth/start on a new machine and sign in with the same GitHub account at /verify. We bind one htmlbin account per GitHub identity.","result":"Both devices share the same user_id with separate tokens."},"limits":{"max_html_bytes":2097152,"max_context_bytes":65536,"max_versions_per_drop":200,"writes_per_minute":60,"writes_per_day":500,"drops_per_account":500,"verification_ttl_seconds":600},"spec":{"openapi":"https://htmlbin.dev/openapi.json","llms_txt":"https://htmlbin.dev/llms.txt","agent_skills_index":"https://htmlbin.dev/.well-known/agent-skills/index.json","api_catalog":"https://htmlbin.dev/.well-known/api-catalog"},"license":"MIT"}