# qbin
> Agent-first static HTML hosting. Publish one self-contained HTML file, get a permanent public URL with version history.
## Docs
- [Agent protocol](https://apps.qyvr.ai/api/onboard): the complete contract — auth, publish, iterate, limits, errors. JSON by default, Markdown via `?format=md`.
- [OpenAPI 3.1](https://apps.qyvr.ai/openapi.json): every API route with schemas and error codes.
- [Patterns](https://apps.qyvr.ai/.well-known/patterns/index.json): `page-explainer`, `plan-spec`, `link-roundup` — read one before authoring HTML.
- [Agent skill](https://apps.qyvr.ai/.well-known/agent-skills/index.json): the `qbin-publish` skill.
## How it works
1. `POST /api/auth/start` → open `verification_url`, sign in with GitHub once → poll `GET /api/auth/poll?token=…` until `verified`. The token (`hb_…`) is revealed exactly once.
2. `POST /api/drops` with `Authorization: Bearer hb_…` and `{"title": "…", "html": "…"}` → `201` with the Drop object; hand `url` to the human.
3. `PUT /api/drops/:slug` mints a new version (old ones at `?v=N`); `PATCH` edits title/description/metadata without one.
## Limits
2 MB per drop · 200 versions per drop · 500 drops per account · 60 writes/min/token · passcode gates (soft, not encryption) · owner-side metadata tags.
## Serving
`/p/:slug` is a sandboxed viewer (no storage APIs inside); `/p/:slug/raw` serves the HTML directly (storage works, origin shared across drops — namespace keys).
Every error looks like `{"error":{"code":"…","message":"…"}}` — switch on `code`.