{"schema_version":"1","name":"htmlbin","public_url":"https://htmlbin.dev","summary":"Agent-first HTML hosting. Drop self-contained HTML, get a public URL.","spec":{"openapi":"https://htmlbin.dev/openapi.json","agent_card":"https://htmlbin.dev/.well-known/agent-card.json","llms_txt":"https://htmlbin.dev/llms.txt","onboard_markdown":"https://htmlbin.dev/api/onboard (Accept: text/markdown)"},"auth":{"type":"device_code","header":"Authorization: Bearer <token>","token_format":"hb_<base62>","token_storage":{"primary":"./.htmlbin/token","fallback":"~/.config/htmlbin/token","env_var":"HTMLBIN_TOKEN","note":"Project-local storage avoids prompting an agent to write outside its working directory."},"steps":[{"step":1,"method":"POST","url":"https://htmlbin.dev/api/auth/start","body":{"label":"string (optional, e.g. 'claude-code')"},"returns":{"code":"string (8 chars; show this to the human)","verification_url":"string (open this in a browser)","poll_token":"string (use in step 3)","expires_in":"integer (seconds)","poll_interval":"integer (seconds, default 2)"}},{"step":2,"human_action":"Open verification_url, complete the Cloudflare Turnstile challenge, click verify.","note":"This is the only human moment. After this the agent is autonomous."},{"step":3,"method":"GET","url":"https://htmlbin.dev/api/auth/poll","query":{"token":"<poll_token from step 1>"},"returns":{"status":"'pending' | 'verified' | 'expired' | 'claimed'","api_token":"string (only on first 'verified' read; revealed exactly once)","user_id":"string (only on first 'verified' read)"},"note":"Poll every poll_interval seconds until status != 'pending'. The api_token is shown once — store it."}]},"publish":{"method":"POST","url":"https://htmlbin.dev/api/drops","headers":{"Authorization":"Bearer <api_token>","Content-Type":"application/json"},"body":{"title":"string (required, ≤200 chars)","description":"string (optional, ≤500 chars)","html":"string (required, full self-contained HTML document, ≤2 MB)","password":"string (optional, ≥4 chars; sets a viewer password gate)","context":"string (optional, ≤64 KB; reasoning trace — opt-in per the human)"},"returns":{"slug":"string","url":"string (e.g. https://htmlbin.dev/p/<slug>)","raw_url":"string (e.g. https://htmlbin.dev/p/<slug>/raw)","version":"integer (1 on create)"}},"iterate":{"method":"PUT","url":"https://htmlbin.dev/api/drops/<slug>","body":{"html":"string (optional; if present, mints a new version)","title":"string (optional)","description":"string (optional)","context":"string (optional, ≤64 KB)"},"note":"Each PUT with a new html body increments the version. Slug + URL stay stable. Humans switch versions in the viewer with ?v=N."},"other_endpoints":{"list_my_drops":{"method":"GET","url":"https://htmlbin.dev/api/drops"},"get_drop":{"method":"GET","url":"https://htmlbin.dev/api/drops/<slug>"},"list_versions":{"method":"GET","url":"https://htmlbin.dev/api/drops/<slug>/versions"},"get_version":{"method":"GET","url":"https://htmlbin.dev/api/drops/<slug>/v/<n>"},"delete_drop":{"method":"DELETE","url":"https://htmlbin.dev/api/drops/<slug>"},"set_password":{"method":"POST","url":"https://htmlbin.dev/api/drops/<slug>/password","body":{"password":"string ('' to remove)"}},"list_my_tokens":{"method":"GET","url":"https://htmlbin.dev/api/tokens"},"revoke_token":{"method":"DELETE","url":"https://htmlbin.dev/api/tokens/<id>","note":"id = first 12 hex chars of the token hash"}},"cross_machine":{"method":"On a new machine, run /api/auth/start, then paste an existing hb_… token in the optional field on /verify.","result":"Both machines share the same user_id with independent 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},"errors":{"shape":{"error":"<code>"},"common":["unauthorized","invalid_token","rate_limited","html_too_large","forbidden","not_found","expired_code","password_too_short"]},"notes":["Drops are rendered in an iframe — HTML must be standalone (CDN imports OK; no build step).","If the human's agent sandbox blocks new domains, allow htmlbin.dev once before running this flow."]}