REST API
Base URL: https://doodlebox.app/api/v1
Every write is POST, and the api key only ever travels via the
Authorization: Bearer <api_key> header — never a URL parameter, never in
the request body (changed 2026-09-03, for security: a key in a URL can land in access logs,
proxy logs, or browser history). No login is needed for the first publish.
Endpoints
| Method & path | Auth | Purpose |
|---|---|---|
POST /publish | optional (header) | Create and publish a project |
POST /update | required (header) | Change one file, same URL, new version |
POST /delete-file | required (header) | Remove one file from a project |
POST /signup | none | Create an account without publishing yet |
GET /project/{id} | optional (header) | Metadata; +files with owner's key |
GET /project/{id}/stats | none | Live player count, plays, likes |
GET /whoami | required (header) | Account + project list for a key |
GET /export | required (header) | Download all account projects as a ZIP |
Publish
POST https://doodlebox.app/api/v1/publish
Content-Type: application/json
{"content": "PGgxPk15IEdhbWU8L2gxPg", "title": "My Game"}
content is your file's bytes, base64 or base64url. It always becomes
index.html: write self-contained HTML/CSS/JS in one file, no external references.
Accepts up to 100 MB of content. Standard base64 is accepted directly;
base64url is also accepted. Use content_encoding=base64, base64url,
gzip+base64, or gzip+base64url to state the format explicitly.
For very large files, chunking is still available: send part=1 first for each
upload_id. Later parts are rejected until part 1 arrives; after that, remaining parts
may arrive in any order.
Optional parameters
| Param | What it does |
|---|---|
handle | Custom username for a brand-new account, instead of a generated one like swift-dragon-42. |
email | Required when creating a brand-new account (no api key yet) — optional after that, and can be added on any later call too. Sends a real verification link. |
lang | Language the user is speaking, e.g. pt, ja. |
To publish to an account you already have a key for, send it via
Authorization: Bearer <api_key> — omit the header for a brand-new account.
On success, the response includes both api_key (account-wide) and
project_api_key (scoped to just the new project) — prefer project_api_key
for future updates to this project, it's safer if it ever leaks.
Update
POST https://doodlebox.app/api/v1/update
Authorization: Bearer <api_key>
Content-Type: application/json
{"project_id": "ab12cd34", "filename": "style.css", "content": "Ym9keXtjb2xvcjpyZWR9"}
filename and content are required; project_id
is optional when using an account-wide key (omit it to target the account's most-recently-updated
project — a scoped key must always send it explicitly). filename can be any file
already in the project, or a new one. Accepts up to 100 MB; encoding and
content_encoding rules are the same as publish.
Delete a file
POST https://doodlebox.app/api/v1/delete-file
Authorization: Bearer <api_key>
Content-Type: application/json
{"project_id": "ab12cd34", "filename": "old-style.css"}
Removes one file from a project. index.html (or a standalone
project's primary file) can never be deleted this way — edit its content instead, or use
/edit on the website with "replace everything" to restructure the whole project.
Export
curl -fL https://doodlebox.app/api/v1/export -H 'Authorization: Bearer <api_key>' -o doodlebox-export.zip
Downloads a read-only ZIP containing all projects in the account, a
manifest.json, and binary files in their original form. The archive excludes
internal .git directories and does not change anything on the server.
Signup
POST https://doodlebox.app/api/v1/signup
Content-Type: application/json
{"handle": "cool-builder", "email": "..."}
Creates an account without publishing anything — both fields optional.
If handle is taken, a numeric suffix is appended automatically instead of an error
(check the handle field in the response for what was actually used). Returns
api_key, same as publish — reuse it on a later call instead of creating a second
account. Mostly useful when you want the account settled before there's a file ready; otherwise
publish already creates one on first use.
Reusing the same account
Hold onto the api_key from your first publish and send it as
Authorization: Bearer <api_key> on every later call in the same conversation.
Publishing a second app, or updating the first one, both land on the same account without asking
the user anything again. Prefer project_api_key (returned by publish, scoped to just
that one project) over the account-wide api_key when you only need to touch one
project. Renaming the handle, changing the recovery email, or minting additional scoped keys is
web-only today — via a logged-in browser session at /account — there is no API
endpoint for any of that.
Errors
Error responses include error, message, and usually a hint
with a corrected example — the API is written to be self-correcting for an AI client.
Full reference, written for an AI to read directly: /llms.txt.