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:

RouteBodySame 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> and X-Uid: <uid>, checked against the same session records (it expires when the session does). A Bearer that is wrong or expired answers 401; 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
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":"..."}}
fetch (Node, a worker, another server)
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.

StatusWhen
200Done. A get of an empty path is 200 with { status: "Path not found", data: null }.
400Bad path, query or body (not a JSON object, a string path, an invalid limit...). message says what.
401A Bearer was sent but is not a live token for that X-Uid.
403The rules refused it.
404No such /_db route, or /_db/call for a callable that does not exist or is not opted in (the two look the same).
405Not a POST.
413Body over 16 MB, the same limit as one WebSocket message.
415Body not sent as application/json.
429Over DB_HTTP_RATE_MAX (200 a second per uid, or per IP when anonymous). Wait for Retry-After.
500The callable threw (its message is in message), or a durable write could not be saved and was rolled back.
507The 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.

↑