Bool’s HTTP API
Everything the bool CLI and the MCP server do, they do
over the same HTTP API you can call yourself — with curl, a script, or a CI job.
Use it to list your projects, fetch a project’s connection config and generated
types, publish a new version, and read your app’s data key.
- Base URL:
https://bool.com - Auth:
Authorization: Bearer <personal access token> - Format: JSON in, JSON out (one endpoint returns TypeScript as plain text)
Two different keys show up in Bool, and they’re not interchangeable. A personal access token (
bool_live_…) is you, and it talks to this API — the platform. A project data key (boolsk_…) belongs to one app, and it talks to that app’s data over REST — see Your app’s data API at the end of this page.
Get a token
Create a personal access token at Settings → API tokens → New token. The value is shown once — copy it then, because Bool only stores a hash of it and can’t show it again. Treat it like a password.
Two things to know about a token:
- It carries your permissions. It can’t do anything to a project you couldn’t do yourself in the editor.
- It’s bound to a single workspace, and only ever acts there. Requests that would touch another workspace’s project fail as if the project didn’t exist. Need to script against two workspaces? Mint one token per workspace.
Tokens can be given an expiry, and can be revoked at any time from the same settings page — a revoked token stops working immediately.
Every request sends it as a bearer token:
export BOOL_TOKEN=bool_live_...
curl -H "Authorization: Bearer $BOOL_TOKEN" \
https://bool.com/api/projectsThe CLI reads the same value from BOOL_TOKEN (or --token), so a shell that’s
set up for bool is already set up for curl.
Endpoints
List your projects
GET /api/projectsReturns an array of the projects in the token’s workspace, newest-updated first.
Each item is the full project record — its id (what every other endpoint takes),
name, slug, runtimeVersion, visibility, and timestamps.
curl -H "Authorization: Bearer $BOOL_TOKEN" \
https://bool.com/api/projectsGet one project
GET /api/projects/{id}The project record plus a files array — every file in the project, sorted by
path. Any level of access to the project is enough.
Create a project
POST /api/projectsBody: { "name": "...", "description": "...", "template": "..." } — all optional.
Responds 201 with the new project record.
curl -X POST https://bool.com/api/projects \
-H "Authorization: Bearer $BOOL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"my-todos"}'Creating a project this way places it in your active workspace (the one selected in the web app), not the token’s bound workspace. If which workspace it lands in matters, create it with
bool create, the MCPdrop_projecttool, or the web app instead.
Get a project’s connection config
GET /api/projects/{id}/connectionEverything a bool-sdk client outside Bool needs to point at the project:
{
"projectId": "…",
"name": "My Todos",
"slug": "my-todos",
"schema": "app_…",
"appOrigin": "https://bool.so",
"appUrl": "https://my-todos.bool.so",
"gatewayUrl": "https://bool.so/served/my-todos/_bool/v1",
"supabaseUrl": "…",
"supabaseAnonKey": "…"
}These are all public values — no secret is in this response, so it’s safe to
commit (bool link writes it to bool.config.json). Any level of project access
can read it.
A project created before Bool’s gateway runtime existed can’t be used as a
backend from outside, and returns 409 with
{"error":"not_gateway_project"}. Either start a new project, or have Bool
make an upgraded copy
of the old one and point at that; see Before you
start on the CLI page.
Get generated TypeScript types
GET /api/projects/{id}/entities/typesReturns the project’s entity types as a single .d.ts file — plain text, not
JSON. This is what bool types fetches. Re-fetch it after your data model
changes.
curl -H "Authorization: Bearer $BOOL_TOKEN" \
https://bool.com/api/projects/$ID/entities/types > bool/types.d.tsReveal or rotate the app’s data key
GET /api/projects/{id}/api-key # reveal (creates it on first read)
POST /api/projects/{id}/api-key # rotateBoth return { "apiKey": "boolsk_…" }. This is the project’s admin data key:
it reads and writes every row in the app, so it’s owner-only — a
collaborator’s token gets a 404. Rotating kills the previous key immediately.
curl -H "Authorization: Bearer $BOOL_TOKEN" \
https://bool.com/api/projects/$ID/api-keyKeep it out of client-side code and out of git. bool link writes it to
.env.bool and gitignores that file for you.
Publish a new version
POST /api/dropsBody: { "project_id": "<id>" } (required — this endpoint deploys a new version
of an existing project). It takes publish rights on the target, and the new
version keeps the project’s current workspace and visibility.
The response is an upload slot:
{
"drop_id": "…",
"upload_url": "https://…",
"upload_method": "PUT",
"upload_headers": { "…": "…" },
"status_url": "https://…",
"expires_at": "2026-07-24T12:00:00.000Z",
"max_upload_size_bytes": 10485760
}Publishing is three steps:
POST /api/dropsto get the slot above.- Upload a ZIP of your app’s source (not a build) to
upload_urlusingupload_methodandupload_headers. - Poll
status_urluntil the status settles.
# 1. Ask for an upload slot
curl -X POST https://bool.com/api/drops \
-H "Authorization: Bearer $BOOL_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"project_id\":\"$ID\"}"
# 2. Upload the source archive
curl -X PUT --upload-file app.zip "$UPLOAD_URL"
# 3. Poll for the result
curl "$STATUS_URL"status_url is pre-signed and scoped to that one drop, so polling it needs no
token. It returns:
{
"drop_id": "…",
"status": "building",
"project_id": "…",
"deployment_id": null,
"url": null,
"error": null
}status moves through awaiting_upload → uploaded → validating → queued →
building → publishing → ready, and can end at failed, expired, or
canceled. On ready, url is the live app. On failed, error explains why.
Poll every couple of seconds, not in a hot loop — the status endpoint rate-limits
and answers 429 with a Retry-After header if you push it. Bool also caps how
much you can publish in a window; over the cap, the POST /api/drops call itself
returns 429.
If all you want is “deploy this folder,” bool deploy does these three steps for
you, including zipping the right files.
Errors
Errors come back as { "error": "..." } with a conventional status code:
| Status | What it means |
|---|---|
401 | No token, or the token is invalid, expired, or revoked. |
404 | The project doesn’t exist, isn’t in the token’s workspace, or you don’t have the access this endpoint needs. Owner-only endpoints return 404, not 403, so a token can’t be used to probe for projects. |
409 | The project can’t do this — e.g. an older-runtime project asked for its connection config. |
429 | Too many requests, or a publish quota is exhausted. Honor Retry-After when it’s present. |
503 | A capability isn’t configured on this deployment (e.g. data keys are unavailable). |
Because a missing permission looks the same as a missing project, treat 404 as
“not available to this token” rather than “deleted.”
Your app’s data API
The endpoints above manage projects. Reading and writing the data inside a
published app is a separate surface with its own key: your project’s boolsk_
data key, sent as an api_key header to the app’s own origin.
curl -H "api_key: boolsk_..." \
"https://my-todos.bool.so/_bool/v1/db/rest/v1/todos?select=*"Open your project’s Dashboard → API for the exact URLs, the field list for
every model, and copy-paste snippets — that tab is generated from your app’s
actual data models, so it’s always current. In app code, prefer the SDK
(bool.entities.todos.list()) over raw REST — the SDK
reference covers the whole surface.
Related
- SDK reference — the
bool-sdkclient your app code uses - Develop locally (CLI) — the
boolcommands built on this API - Connect your AI (MCP) — the same powers for coding agents
- Database — entities, records, and your data model
- Publishing — how deploys go live and who can see them