# hobing publishing API Base: https://hobing.link. Start with https://hobing.link/skill.md to choose account or anonymous publishing. All paths below use this base. JSON requests and responses unless stated. Attach Authorization: Bearer to every account request. Timestamps are ISO 8601 UTC. No public CLI package or MCP installation is required. ## Identity and quotas Account mode only: GET /v1/me → account identity. GET /v1/config → storage/site limits, TTL and republish cooldown. Site total: anonymous/Free 25 MiB, Pro 200 MiB, File counts: anonymous 100, Free 300, Pro 1,000. There is no smaller per-file quota; maxFileBytes remains a compatibility alias equal to maxSiteBytes. Account storage remains Free 100 MiB / Pro 2 GiB. In account mode it also reflects the current plan; without Authorization, publishingMode:"anonymous" identifies no account and plan:"free" is only a limit profile. The anonymous object gives dailyNetworkPublishes (30 by default) and networkCounterShared:false. The separate network.dailyPublishes safety ceiling (600 by default) covers both modes. Account mode only: GET /v1/usage → used, limits and resetsAt. Anonymous mode must not call account-only endpoints. Monthly usage resets on the UTC calendar month, separately from subscription renewal. Requests include assets, HEAD and missing files on active sites. Accepted upload attempts, updates and republishes consume publishing quota; hourly/daily limits also apply. No automatic overage billing. ## Inline bundles POST /v1/publishes → 201 project. Body: {"title":"My site","spa":false,"files":[{"path":"index.html","encoding":"utf8","content":"

Hello

"}]}. Binary files use encoding:"base64". Root index.html required. SPA true enables fallback for extensionless HTML navigation. This JSON endpoint has a 15 MiB request ceiling, including base64 overhead; honor the smaller file/site limits from config. PUT /v1/projects/ID/files → updated project; same bundle body, complete replacement. Target must be online. Does not extend expiry or change URL. ## Staged uploads (all modes; required for large bundles) 1. POST /v1/uploads with {"title":"My site","spa":false,"files":[{"path":"index.html","size":123,"digest":"lowercase SHA-256 of exact bytes"}]}. Add projectId for an update. For a file over 8 MiB, replace digest with chunks: an ordered array of SHA-256 digests, one per 8 MiB segment (last may be smaller). Returns id, expiresAt and chunkBytes. Reserves storage and consumes one publish operation for the entire upload. Anonymous creation omits Authorization; it returns a private uploadToken. Use that token as the Bearer credential ONLY for this upload’s PUT/commit/cancel requests. Never use it as an account credential. Account uploads keep using their account/agent credential. 2. PUT /v1/uploads/ID/0, /1, etc. with Content-Type: application/octet-stream, bearer auth and exact bytes for the zero-based manifest entry. For chunked files, PUT /v1/uploads/ID/FILE_INDEX?chunk=0, then chunk=1, etc., sequentially; send exactly 8 MiB except the final remainder. Hashes and lengths are verified before assembly. Completed chunk retries are idempotent. Unchunked PUT is limited to 16 MiB; use chunks above 8 MiB. A checksum failure requires a new upload. 3. POST /v1/uploads/ID/commit with {} → 201 project (anonymous includes private managementToken and claimUrl). DELETE /v1/uploads/ID cancels an unfinished upload. Retry does not extend its deadline. Pro publishes default to always-online while eligible. Free publishes are temporary until an available retention slot is selected. ## Project management GET /v1/projects → {projects:[...]}; GET /v1/projects/ID → title,icon,status,url,expiresAt,permanent,revision,fileCount,bytes,republishAvailableAt. Check ownership and exact target before changes. PATCH /v1/projects/ID with {"title":"My site"} or {"icon":"🌻"} → update saved site metadata as its owner. Names: 1–80 characters; icons: short label/emoji or small PNG/WebP data URL (max 24 KiB encoded); null resets the icon. Keeps address, expiry and publishing quota unchanged. POST /v1/projects/ID/unpublish → offline; files, address and expiry retained. POST /v1/projects/ID/resume → latest address online; no new expiry. Expired, blocked and plan-paused sites cannot bypass restrictions. POST /v1/projects/ID/republish → NEW random address and TTL; previous random address remains revoked. Requires explicit user request and cooldown completion. Pro custom addresses remain stable. POST /v1/projects/ID/retention with {"permanent":true} → use an available always-online slot while the site is online. false releases the slot and restores the original expiry, which may already be past. Turning off does not free a slot. GET /v1/projects/ID/download → file manifest; GET /v1/projects/ID/download?path=ENCODED_PATH → raw file bytes. GET /v1/projects/ID/export → JSON/base64 bundle for sites up to 10 MiB. Downloads remain available after expiry for saved sites. DELETE /v1/projects/ID → delete the site and revoke serving. Requires explicit user request. POST /v1/projects/ID/claim with {"claimToken":"..."} → save an unclaimed, unexpired anonymous site to the authenticated account without extending expiry. Claim tokens are private. ## Authorization lifecycle POST /v1/agent/device {name} → deviceCode, userCode, verificationUriComplete, expiresIn, interval. Only the user reviews/approves in their browser; the agent polls /v1/agent/token. Never display the deviceCode or token response. Credentials last 30 days, up to 20 active grants/account. GET /v1/agent/authorizations and DELETE /v1/agent/authorizations/ID are browser-only; agents revoke themselves with DELETE /v1/agent/session. Password resets revoke agent grants. Credentials cannot access billing, identity changes, domain authorization or other grants. ## Errors / recovery Errors: {"error":{"code":"...","message":"...","retryAfter":60,"retryAt":"..."}} (retry fields optional). 401: stop and reconnect. 403: respect ownership/scope/plan restrictions. 409: reload state before retrying; never duplicate a publish blindly. 410: request expired/handled. 413: check limits or use staged upload. 429: honor Retry-After/retryAfter; never evade quotas. After an ambiguous publish result, list projects before attempting another creation. Ask the user to choose account login or anonymous if they have not already chosen. Only explicitly anonymous requests omit authorization, even if a saved credential exists. Anonymous publishes have a separate daily network counter. Account publishes use per-account quotas. Both also obey a higher shared network safety ceiling and platform caps; use the returned reset time on 429. Never silently switch modes or change networks to evade limits. Account mode is available only if the user chooses it and remains subject to its own limits. Their response includes managementToken and claimUrl; share only url publicly. Unclaimed temporary sites are cleaned up after expiry. Signed-in files remain until deletion, subject to service terms. See https://hobing.link/docs/ for product help and https://hobing.link/feedback/ for private issue reports; never submit secrets.