Kiroku API

Conventions & contract

Why the endpoints all look the same: the auth model, the response envelope, the error model, and the 407 reauthentication pattern.

The auth model

Auth is enforced per route, in the Express app — the function itself is publicly invokable. Three tiers:

The API never mints or issues credentials of its own — Firebase Auth stays the identity provider, and there are no API keys.

The response envelope

Every /v1 business endpoint returns the same envelope, so the Kiroku app's existing response middleware can apply it unchanged. This is non-negotiable — it is the reason the API exists.

{
  "jsonCode": 200,        // success switch; HTTP status is mirrored into it
  "onyxData": [           // OnyxUpdate[] — applied via Onyx.update(onyxData)
    { "onyxMethod": "merge" | "set" | "mergecollection" | "clear", "key": "<ONYXKEY>", "value": <any> }
  ],
  "lastUpdateID": 0,      // optional, incremental-sync ordering
  "previousUpdateID": 0,  // optional
  "requestID": "..."      // optional
}

The error model

A 200 with empty onyxData ("no-op success") is deliberate and appears in several places — the operation succeeded, there is simply nothing for the client to merge.

Reauthentication — the 407 pattern

When the Firebase ID token has expired (as opposed to being missing or invalid), the API responds with HTTP 200 and the envelope:

{ "jsonCode": 407, "onyxData": [] }

The 407-inside-HTTP-200 is deliberate: the client treats any non-2xx HTTP status as a network error and would never inspect jsonCode. By answering 200, the client's reauthentication middleware sees the 407, refreshes the Firebase ID token, and replays the request. Missing, malformed, or revoked tokens stay a plain HTTP 401 — a refresh would not help there.

See also