HTTP Data API
For callers that cannot keep a WebSocket open (a script, a cron job, another server, a device), the engine answers the same data calls over plain HTTP. Engine 1.13+. Every route is POST, takes a JSON body and answers JSON:
| Route | Body | Same as |
|---|---|---|
POST /_db/get | { path } | client.get |
POST /_db/set | { path, data } | client.set |
POST /_db/update | { path, data } | client.update |
POST /_db/remove | { path } | client.remove |
POST /_db/increment | { path, data } | client.increment |
POST /_db/query | { path, childPath, query, orderBy, desc, limit, startAt, cursor, count } | client.query |
POST /_db/call | { name, data } | client.callableFunction, for callables registered with { http: true } |
Writes also take durable: true (answered once the write is on disk, see Durable Writes) and opId (a retry with the same opId gets the first reply and is applied once, so retrying an increment is safe). Paths are arrays, exactly as in the SDK.
It is the socket, over HTTP
A request becomes the same message a WebSocket sends and goes through the same code: your security rules decide, triggers fire, and every browser subscribed to the path gets the change live. Nothing is reachable over HTTP that is not already reachable over a socket, except callables, which are opt-in. Subscriptions need a socket and have no HTTP route.
Who is calling
- A browser on your site: the session cookies, as for everything else. They are
SameSite=Strict, so another site cannot send them. - Anything else:
Authorization: Bearer <token>andX-Uid: <uid>, checked against the same session records (it expires when the session does). A Bearer that is wrong or expired answers401; it never falls back to anonymous. - Neither: anonymous, and the rules decide, as for an anonymous socket.
There are no CORS headers, so a page on another site cannot call it from the browser. Scripts and servers can.
curl -X POST https://your-app.nukebase.com/_db/set \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" -H "X-Uid: $UID" \
-d '{"path": ["sensors", "garage", "temp"], "data": 21.5}'
# {"status":"Success"}
curl -X POST https://your-app.nukebase.com/_db/call \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" -H "X-Uid: $UID" \
-d '{"name": "addOrder", "data": {"item": "mug", "qty": 2}}'
# {"status":"Success","data":{"orderId":"..."}}
async function db(op, body) {
const r = await fetch("https://your-app.nukebase.com/_db/" + op, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + process.env.NB_TOKEN,
"X-Uid": process.env.NB_UID
},
body: JSON.stringify(body)
});
if (r.status === 429) { await new Promise(s => setTimeout(s, 1000)); return db(op, body); }
return r.json();
}
const { data } = await db("query", { path: ["orders"], childPath: ["status"], query: "child == 'new'" });
await db("increment", { path: ["stats"], data: { visits: 1 }, opId: crypto.randomUUID() });
Answers
The body is the socket's reply without action and requestId: { status, data }, plus the query metadata for windowed queries.
| Status | When |
|---|---|
200 | Done. A get of an empty path is 200 with { status: "Path not found", data: null }. |
400 | Bad path, query or body (not a JSON object, a string path, an invalid limit...). message says what. |
401 | A Bearer was sent but is not a live token for that X-Uid. |
403 | The rules refused it. |
404 | No such /_db route, or /_db/call for a callable that does not exist or is not opted in (the two look the same). |
405 | Not a POST. |
413 | Body over 16 MB, the same limit as one WebSocket message. |
415 | Body not sent as application/json. |
429 | Over DB_HTTP_RATE_MAX (200 a second per uid, or per IP when anonymous). Wait for Retry-After. |
500 | The callable threw (its message is in message), or a durable write could not be saved and was rolled back. |
507 | The project's disk is full; removes still work. |
Actions, not raw paths, for integrations. Give an outside system one callable that checks its input and writes what it should (addOrder), rather than write access to the paths themselves. Use the data routes for simple reads and writes your rules already cover.
Not for third-party webhooks. Stripe, GitHub and the like post their own body and sign the exact bytes. Give them a postWithBody route of your own.
/_db/ belongs to the engine, like /_file/: do not add routes of your own under it.