Skip to main content

Authentication

Partners authenticate with an API key — a pat_-prefixed bearer token — on every request:

curl https://api.example.com/api/v1/loans \
-H "Authorization: Bearer pat_1a2b3c…"

How keys are scoped

Keys are minted under a shared, login-less service account (partner-api@service.local) that holds the Partner role. This decouples partner keys from any staff member's account — a key outlives personnel changes and can't be widened by changes to a human's permissions.

A key's effective permissions are the intersection of the service account's permissions and the key's own scopes. Partner keys are restricted to the partner-loan family:

  • partner.loans.read — read loans (GET).
  • partner.loans.write — create and service loans (POST).

Because the scopes never include loans.*, the key authenticates fine but is forbidden on the internal admin /api/loans (a 403, not a 401) — the contract boundary between partners and staff.

Minting a key (staff)

An administrator with partner.keys.manage mints a named key for a partner. The name identifies the partner; the raw key is returned once and never retrievable again:

curl -X POST https://admin.example.com/api/partner-keys \
-H "Content-Type: application/json" \
--cookie "…admin session…" \
-d '{ "name": "acme-partner" }'
{ "id": 42, "name": "acme-partner", "prefix": "pat_1a2b3c4d", "key": "pat_1a2b3c4d…full…" }

You may narrow the scopes (e.g. a read-only key), but never widen them beyond partner.loans.* — the endpoint rejects any other scope with a 400. Hand the key value to the partner over a secure channel; store only the prefix for your own reference.

Read-only vs read-write

A key scoped to partner.loans.read can list and fetch loans but is 403 on any write (create/activate/pay). Give a partner the narrowest key that fits their integration.