Information
- OpenAPI version:
3.1.1
Bookend validates commercial-loan closing packages against the loan approval record, records every step in a hash-chained evidence log, and boards the approved loan to the bank’s core. It runs on-prem inside the bank’s network; nothing here is cloud-hosted.
Every route lives under /v1 on the api container (http://api:8080/v1/…). The app-ui container proxies the same routes under /api on the published port (/api/v1/loans → /v1/loans), so a browser client and the SPA use /api while server-to-server integrations may talk to the api container directly. Requests and responses are JSON (application/json) unless a route says otherwise (file uploads are multipart/form-data; downloads are streamed with a Content-Disposition header).
Two kinds of principal, one bearer scheme (Authorization: Bearer <access token>, RS256 JWT; the public key is at /v1/.well-known/jwks.json):
POST /v1/auth/login (email + password) or through an emailed link (POST /v1/auth/otp/request then POST /v1/auth/otp/redeem). Both return an access token (auth.access_token_minutes, default 15) and a rotating refresh token: call POST /v1/auth/refresh before the access token expires and replace both tokens; reusing a rotated refresh token revokes every session of that user. Keep tokens in memory; there are no cookies or server sessions. Authorization is by role: admin, manager, specialist, boarding_checker, auditor_readonly.POST /v1/api-keys) and exchange it at POST /v1/auth/token for a short-lived access token with no refresh token. Authorization is by scope: status:read (read loans, findings, pipeline, boarding and wire status), intake:write (create packages, upload documents and the LAR, reprocess) and evidence:read (evidence events, verification and the evidence packet). Routes that change state through a person; review decisions, boarding and wire approvals, sealing; require a user token and refuse API keys with 403.Each operation’s description names the roles and scopes it accepts. Segregation of duties (the person who staged a boarding or wire cannot approve it) is enforced by the service at approval time and surfaces as 403.
Every error is RFC 9457 application/problem+json with status, title, detail, instance (the request path) and a traceId that matches the structured log line. Field validation failures are 400 with an errors array of { field, message }; 422 means the request was well-formed but a policy refuses it (license expired, activation blockers, approval blockers, package size, adapter refusal) and carries the reason in detail. Also used: 401 bad or missing credentials, 403 wrong role, scope or segregation of duties, 404 unknown loan reference, document, finding, user or key, 409 the resource is in a state that does not allow the action (duplicate loan reference without newVersion, wrong loan or record state, already revoked, already overridden), 429 rate limited.
"1250000.00", "0.0725"), never floating-point numbers. Dates and timestamps are ISO-8601 in UTC.boarding_staged).page (1-based) and size (default 50, maximum 200) and answer with the { items, page, size, total } envelope.{ref}), which always resolves to the latest package version; packages are never overwritten.POST /v1/loans/{ref}/boarding/stage accepts an Idempotency-Key header; the same key for the same loan replays the original record instead of staging again./v1, with a much tighter per-address limit on the credential routes (login, sign-in links, API-key exchange, first-admin creation). Rejections are problem+json 429.GET /v1/loans/{ref}/evidence/verify recomputes it.The path prefix is the API version. Within /v1 changes are forward-compatible additions (new optional fields, routes, enum values); clients must ignore properties they do not know. Breaking changes would ship as /v2 alongside /v1. The document served at GET /v1/openapi.json describes the running build; a snapshot per release is kept at docs/api/openapi.json in the repository and is what the generated TypeScript client is built from.
The same operations are available to agents and automations through a Model Context Protocol server at /mcp (streamable HTTP, stateless), authenticated with the same bearer tokens and enforcing the same policies; every tool is a thin call into the service behind the matching REST route, and every call is audited. See the MCP guide in the documentation for the tool list.