Skip to content
Talk to our solutions team

BFF API

BFF has almost no fixed routes. Two are static, and everything else is defined per tenant in configuration and matched at request time:

RoutePurpose
GET /listThe BFF definitions registered for your tenant. Add ?name=<name> for one
GET /health, GET /readyProbes, unauthenticated
anything elseMatched 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.

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.

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.

StatusMeaning
400Request parse or validation failure, or no definition matched the path and method
401Missing or invalid token, as plain text
403The tenant may not perform this operation
404Genuinely nothing to serve
500An 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.

GET /bff/health (get health status of the service)

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)

response:

ready:true

GET /bff/list (lists all bff definitions this product)

response:

{
"bffs": null
}
EndpointPurpose
GET /listBFF endpoints defined for this product
GET /healthLiveness
GET /readyReadiness

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.

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.

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.