API reference
Everything below is generated from the contract at apps/api/openapi/integration-v1.yaml. That file is the single source: the backend test suite checks the running API against it on every run, so this page and the API cannot drift apart.
Remember that every response is wrapped in an envelope — the schemas already include it. See conventions for what that means in practice.
The operations are split by module — pick one from the sidebar: products, orders, customers, health.
The integration surface is how an external system — a POS, an accounting
package, a BI tool — reaches one Bione merchant's data. It is versioned
separately from Bione's internal APIs so a partner's paths do not move when
Bione ships an internal major version.
Two rules that will break a generated client
Every response is wrapped in an envelope. The thing you asked for is in
data; the fields beside it describe the outcome. Dispatch on code — 0
is success, anything else is an error — not on the HTTP status.
Every success is HTTP 200, regardless of verb. A POST that creates a
resource answers 200, not 201. Errors keep their real status (400, 401,
403, 404, 409, 429). A client generated on the assumption that 201 means
"created" will treat every successful create as unhandled.
Conventions
- Money is a string, never a number —
"5000.00". Parse it with a
decimal library and format at display time. Reading it as a float loses
precision on large sums. - Quantities are strings too, in the product's
measureUnit—
"3","1.25". Products sold by weight, volume or length carry decimal
stock ("24.5"); parse quantities with a decimal library, never as a
float. Orders you place take whole pieces only: a product whose
measureUnitis notPCSis refused with code 41002, and a quantity
may still be sent as a whole JSON number. - Timestamps are ISO 8601 strings in UTC.
- Lists are paginated with
pageandpageSizequery parameters and
answer with the shape inPaginated. - Writes are safely retryable. Send an
Idempotency-Keyheader on any
non-GET request and a retry replays the original response instead of
repeating the work. A key is scoped to your API key and to the route and
resource it was sent to: the same key on another route, another resource
or under another API key is a new request, never a replay. Same key with
a different body is refused as a mismatch; retrying while the first call
is still in flight is refused as in-progress. - A route that returns nothing answers with the string
"OK"indata.
Authentication
Send your key in an api-key header. Keys are issued by the merchant from
their Bione company admin and carry a fixed set of scopes; a call for which
your key lacks the scope is refused with 403, and the refusal does not say
which scope was missing. A refused key always answers 401 without saying
whether it was unknown, revoked or expired.