BFF API
How routing works
Section titled “How routing works”BFF has almost no fixed routes. Two are static, and everything else is defined per tenant in configuration and matched at request time:
| Route | Purpose |
|---|---|
GET /list | The BFF definitions registered for your tenant. Add ?name=<name> for one |
GET /health, GET /ready | Probes, unauthenticated |
| anything else | Matched against your tenant’s BFF definitions |
Unmatched paths are not 404s by default: the service installs its dispatcher as the not-found
handler, so any path is a candidate and the answer depends on what your tenant has defined. A
definition supplies a path, a method (defaulting to GET), and the endpoints it stitches
together.
This is why there is no endpoint table here. GET /list is the endpoint table, and it differs
per tenant.
Authentication
Section titled “Authentication”Every route requires a bearer token, including the dynamically matched ones — the dispatcher applies the same guard the static routes use, so a definition cannot expose an unauthenticated route.
Authorization: Bearer <token>The probes are the only unauthenticated surface.
Tenancy
Section titled “Tenancy”The four CPET headers — X-Customer, X-Product, X-Env, X-Tenant — resolve the tenant, and the
tenant decides which BFF definitions exist. The same URL can therefore be a valid endpoint for one
tenant and unmatched for another.
A tenant with no definitions loaded gets an error naming that condition rather than a 404, which is the first thing to check when a route you just declared does not answer.
Errors
Section titled “Errors”| Status | Meaning |
|---|---|
400 | Request parse or validation failure, or no definition matched the path and method |
401 | Missing or invalid token, as plain text |
403 | The tenant may not perform this operation |
404 | Genuinely nothing to serve |
500 | An upstream endpoint in the stitch failed, or an unexpected error |
A 500 here often means one of the stitched upstreams failed rather than BFF itself — check the
definition’s endpoints before suspecting the service.
Health
Section titled “Health”GET /bff/health (get health status of the service)
Example:
Section titled “Example:”response:
{ "healthy": true, "dependencies": {}, "version": ""}The response also carries a memstats object. That is runtime diagnostics, not a contract — see
API conventions. version is whatever the service
set at startup, and most set nothing.
GET /bff/ready (get ready status of the server)
Example:
Section titled “Example:”response:
ready:trueList Definitions
Section titled “List Definitions”GET /bff/list (lists all bff definitions this product)
response:
{ "bffs": null}Endpoints
Section titled “Endpoints”| Endpoint | Purpose |
|---|---|
GET /list | BFF endpoints defined for this product |
GET /health | Liveness |
GET /ready | Readiness |
Product endpoints are declared per tenant and served from the same surface. GET /list is the
inventory, and it is accurate because it is what the runtime resolves against.
Endpoint shape
Section titled “Endpoint shape”A BFF endpoint is declared, not coded: which upstreams to call, how to combine them, what shape to return. Independent calls run in parallel, so an endpoint costs roughly its slowest upstream rather than the sum — which is the latency win over a client making the same calls in sequence.
Failure policy
Section titled “Failure policy”Each upstream is marked as fatal to the response or degrading it. That choice is the most consequential thing in a BFF: too permissive and screens render half-empty with no error, too strict and every screen’s availability is coupled to every service behind it.