Overview
Originating partners integrate with Loanly programmatically through a dedicated, versioned
/api/v1 surface served by a separate host (Loanly.PartnerApi). It exposes the loan
lifecycle only — create, read, activate, and service loans — and nothing of the internal
operations surface (no general ledger, provisions, or audit).
Tenancy model
Partners are part of the one tenant, not owners of a slice of it. There is no partner entity and no per-partner scoping on loans — a partner acts on the tenant's loan book, and the API key's name identifies which partner it's for. The boundary between partners and internal staff is drawn with permissions, not data isolation:
/api/v1requires thepartner.loans.*permissions.- The internal admin
/api/*endpoints require theloans.*(etc.) permissions.
So a partner key can create and service loans but can never reach an internal admin endpoint — it
gets a 403. See Authentication.
Shape of the API
- One host, no worker. The partner host only serves requests; the admin host runs the background sweeps (charging, disbursement dispatch, provisioning). Both share one database.
- Bearer API keys. Every request carries
Authorization: Bearer pat_…. There is no cookie or interactive login. - RFC 7807 errors. Failures come back as ProblemDetails with a
detailmessage and a trace id. - Dev explorer. In development the host serves an OpenAPI document at
/openapi/v1.jsonand a Scalar explorer at/scalar, both scoped to/api/v1/*.
What's deferred
Partner webhooks and outbound call observability are intentionally not hand-rolled — they'll ride on forthcoming framework features. Until then, partners poll the read endpoints for state.