AppBlocks Cloud HTTP API
The AppBlocks Cloud backend exposes a REST-style HTTP API. It is the same API the AppBlocks web application uses, so anything you can do in the UI can also be automated.
Base URL
| Environment | Base URL |
|---|---|
| Production | https://api.appblocks.io |
| Self-hosted | value of the server's API_URL environment variable |
All paths in this reference are relative to the base URL.
Route prefixes
The API is split across a few prefixes that reflect the subsystem behind them:
| Prefix | Contents |
|---|---|
/api/workspaces | Workspaces, members, invites, variables, tenants, audit logs |
/cgg/devices | Devices, variables, tables, commands, firmware, logs, metrics |
/cgg/public/devices | Read-only access to devices with a public dashboard |
/cgg/groups | Device groups |
Authentication
Programmatic access uses API keys. A key is a personal credential: it authenticates as the user who created it, so every workspace, tenant and device permission that applies to that user applies to the key as well.
Creating a key
In the web app, go to Settings → API Keys (/settings/api-keys), give the
key a name, choose its scopes and an optional expiry. The secret is shown
once, at creation time — only its SHA-256 hash is stored, so it cannot be
retrieved again. The same thing can be done over HTTP with
POST /api/account/api-keys.
Keys look like abk_ followed by 32 random bytes:
abk_1a2B3c4D5e6F7g8H9i0JkLmNoPqRsTuVwXyZ...
Using a key
Send it in the x-api-key header, or as a bearer token:
curl -H 'x-api-key: abk_…' https://api.appblocks.io/cgg/devices?count=20
# equivalent
curl -H 'Authorization: Bearer abk_…' https://api.appblocks.io/cgg/devices?count=20
const res = await fetch('https://api.appblocks.io/cgg/devices?count=20', {
headers: { 'x-api-key': process.env.APPBLOCKS_API_KEY },
});
const { count, data } = await res.json();
GET /api/me is the cheapest way to check that a key works and see what it is
allowed to do:
{
"id": "8a3f1c2d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
"email": "me@example.com",
"auth": "apiKey",
"apiKey": { "id": "664e…", "name": "CI deploy", "scopes": ["read", "write"] }
}
Scopes
| Scope | Allows |
|---|---|
read | GET, HEAD and OPTIONS requests. Always present. |
write | Everything else — POST, PUT, PATCH, DELETE |
A key without the write scope that attempts a modifying request is rejected
with 403 {"message":"This API key does not have the write scope"}.
Limits and revocation
- A key may be given an expiry of 1–365 days, or no expiry at all.
- Each user may hold up to 25 active keys.
- Revoking a key takes effect immediately; a revoked or expired key returns
401 {"message":"Invalid or expired API key"}. lastUsedAtis refreshed at most once a minute, so it shows recent use rather than the exact time of the last request.
Everything under /api/account — profile, password and API key management
itself — rejects key authentication with
403 {"message":"This endpoint requires a signed-in session, not an API key"}.
A key can therefore never change the account's credentials or mint further keys.
const res = await fetch('https://api.appblocks.io/cgg/devices?count=20', {
credentials: 'include',
});
CORS reflects the requesting origin and allows credentials, so a browser client on any origin can talk to the API once a session exists. Every endpoint accepts either authentication method, except the account routes noted above.
Endpoints that require no authentication
A handful of routes are intentionally public:
GET /api/projects/examples,/examples/categories,/examples/:idPOST /api/projects/code,/download,/save,/blockgen,/buildGET /api/projects/:id/versions/:versionCode/firmware/:filename(device OTA download)GET /cgg/public/devices/...(devices withpublicDashboard: true)ALL /cgg/webhooks/:id(workflow webhook triggers)GET /api/invites/:token,POST /api/invites/:token/acceptPOST /api/chatwoot/webhook,GET /api/chatwoot/status,GET /api/copilotkit/statusGET /api/tibbits/docs/:model
Everything else returns 401 unauthorized (plain text) when neither an API key
nor a valid session cookie is present.
Deployed devices talk to the cloud over MQTT, authenticating with their
deviceId and device key. The only HTTP endpoint devices use is the OTA
firmware download URL stored on a project version.
Common conventions
Pagination
List endpoints accept start (offset, default 0) and count (page size). The
default page size is 10 for most collections, 20 for logs, metrics and
extensions. Results are sorted by updatedAt descending unless noted.
The response envelope is:
{
"count": 137,
"data": [ /* … */ ]
}
count is the total number of matching documents, not the number returned.
Audit logs use limit/skip instead of count/start, and return
{ logs, total, deviceNames }. Workflow runs clamp count to a maximum of 100.
Search
Where supported, search=<text> filters by name using a case-insensitive
regular expression. Device and workspace log endpoints apply search to the log
message instead.
Field filters
Collection endpoints for devices, projects, device logs and metrics accept
ad-hoc filters encoded in the query string as <field>___<operator>=<value>:
| Operator suffix | Meaning |
|---|---|
___eq | equals |
___ne | not equal |
___gt | greater than |
___lt | less than |
___gte | greater than or equal |
___lte | less than or equal |
For example, only connected devices:
GET /cgg/devices?state.connected___eq=true&count=50
An empty value is treated as null, which is useful for "field is not set"
queries.
Time ranges
Log and metric endpoints accept startTime and endTime as any
Date-parseable string (ISO 8601 is recommended). When omitted, endTime
defaults to now and startTime to 24 hours earlier.
Workspace and tenant scoping
Most collections exist either in a user's personal space or inside a workspace:
- Without
workspace, the endpoint returns the caller's personal items — documents with no workspace. - With
workspace=<workspaceId>, it returns that workspace's items, after verifying the caller has access. - Adding
tenant=<tenantId>narrows the result to a tenant. For devices, groups, logs and metrics, passingworkspacewithouttenantreturns only the items that are not assigned to a tenant.
Error responses
| Status | Meaning |
|---|---|
400 | Missing/invalid input, or the referenced object is not visible to the caller |
401 | No valid credentials (unauthorized as plain text, {"error":"Unauthorized"}, or {"message":"Invalid or expired API key"}) |
403 | Authenticated but the role or the key's scope is insufficient ({"message":"…"}) |
404 | Object does not exist |
500 | Server error (error as plain text, or {"message":"…"}) |
503 | An optional integration (AI, Chatwoot) is not configured |
Error bodies are not fully consistent: newer routes return
{ "message": "…" } or { "error": "…" }, while older ones send an empty body
with the status code. Treat any non-2xx status as a failure and do not depend on
a body being present.
Roles and permissions
Two independent membership models control access to workspace content.
Workspace roles
| Role | Capabilities |
|---|---|
owner | Everything, including deleting the workspace. Set at creation time. |
admin | Manage members, invites, variables and all workspace content |
operator | Read-only on devices and groups; may edit projects |
member | Read and edit workspace content (devices, dashboards, workflows, projects) |
Attempting a write as an operator returns
403 {"message":"Operators have read-only access"}.
Tenant roles
Tenants are sub-organizations inside a workspace, used to segment devices and users for end customers.
| Role | Capabilities |
|---|---|
admin | Manage tenant users, invites and variables; add devices/groups to the tenant |
member | Read the tenant's devices and dashboards |
A user who belongs only to a tenant (a tenant-only member) sees the workspace
in a reduced form: member list, workspace variables and tenant variable
templates are stripped, and isTenantOnlyMember: true is returned. Tenant-only
members without the tenant admin role cannot write device state variables or
tables, and cannot edit dashboards, SCADA screens, workflows or projects.
Workspace owner and operator roles have implicit access to every tenant in
the workspace.
Reference sections
- Devices — devices, variables, tables, commands, firmware, logs, metrics
- Device Groups — grouping devices and pushing shared configuration
- Workspaces & Tenants — workspaces, members, invites, variables, tenants, audit logs