Core concepts
The handful of ideas that the rest of the documentation assumes you know: the two API rings, the object graph that ties applications to decisions, payments and accounts, the sandbox/live split, our ID and money conventions, and the states a loan application moves through from creation to funding.
The Credicorp API is REST over HTTPS. Resources are JSON, requests are authenticated with bearer tokens, and the same object shapes come back from reads, writes and webhook payloads. Read this page once and the reference sections will feel familiar.
API rings
Every endpoint belongs to one of two rings. The ring is the first path segment after the host and it decides who may call the endpoint and how it authenticates.
| Ring | Audience | Auth | Typical use |
|---|---|---|---|
public/v1 | End users & browsers | OIDC user token (PKCE) | “Sign in with Credicorp”, a borrower reading their own account, consented identity claims. |
partner/v1 | Your backend | OAuth client-credentials | Creating applications, reading decisions, taking payments, servicing funded accounts. |
The two rings never share a token. A partner/v1 client-credentials token acts as your organisation and can see the applications and accounts you originated; a public/v1 token acts as a single signed-in person and is scoped to their own data. Most integrations live almost entirely in partner/v1; reach for public/v1 only when a real human is present and consenting. See OAuth 2.0 for both flows.
The ring is not a version label — v1 is the API version and is shared across rings. We add fields without bumping the version; breaking changes ship under a new version with a deprecation window announced in the changelog.
Core objects
Six resources carry almost all the weight. They form a chain: an application produces a decision, an accepted decision funds an account, and an account is repaid through payments. Identity sits alongside, attaching verified people to the borrower.
| Object | Prefix | What it is |
|---|---|---|
application | app_ | A request to borrow, for one UK incorporated entity. The entry point to lending. |
decision | dec_ | The authoritative AI outcome for an application: approve / refer / decline, plus the offer and reasons. |
account | acc_ | A funded loan. Holds the balance, schedule and servicing state once money is disbursed. |
payment | pay_ | A movement of money — a disbursement out, or a repayment collected in via open banking. |
identity | idv_ | A verified person (a director or beneficial owner) attached to the borrowing entity. |
event | evt_ | An immutable record of something that happened, delivered to your webhook endpoints. |
Every object carries the same envelope fields: a string id, an object type, a created_at timestamp, and — where you supplied one — your reference. References are echoed verbatim onto child objects, so a reference you set on an application appears on its decision, account and payments, which makes correlation in your own systems trivial.
Environments
There are two fully isolated environments. They share the same code, the same object shapes and the same SDKs — only the host, your credentials and the data differ. Nothing crosses between them.
| Environment | Base URL | Behaviour |
|---|---|---|
| Sandbox | https://sandbox.credicorp.co.uk | Deterministic. No real money, no real identity checks. Decisions are driven by magic amounts and test company numbers. |
| Live | https://api.credicorp.co.uk | Real borrowers, real Companies House and identity checks, real disbursement and repayment. |
Sandbox credentials are prefixed cid_sbx_ / csk_sbx_; live credentials use cid_live_ / csk_live_. Because the prefix is visible on the key, an accidental cross-environment call fails loudly at authentication rather than doing something surprising. Build and certify against sandbox, then change the base URL and credentials — no other code changes are needed to go live.
Identifiers & money
Object IDs are opaque, prefixed strings — never parse meaning out of the characters after the prefix, and never assume a length. Treat them as the canonical reference for retrieval and storage.
- ID shape
<prefix>_<random>, e.g.app_8Kd2c9Qm. The prefix tells you the type.- Money
- Always integer minor units (pence) in fields suffixed
_pence. Never floats. - Rates
- Basis points in fields suffixed
_bps.1490means 14.90%. - Currency
- GBP only. There is no
currencyfield to set. - Timestamps
- RFC 3339 / ISO 8601 in UTC, e.g.
2026-06-29T10:01:12Z.
Pence, not pounds. Sending "amount_pence": 25000 requests £250, not £25,000. The single most common integration bug is a missing factor of one hundred — assert it in your tests.
Conventions
The whole API follows a small set of rules, so once you have learned them for one endpoint they hold everywhere.
- Authentication. Bearer token in the
Authorizationheader on every request. No tokens in query strings. - Idempotency. Send an
Idempotency-Keyon everyPOSTthat creates or moves money. Retrying with the same key returns the original result instead of duplicating it — see Idempotency. - Pagination. List endpoints are cursor-based: pass
limitand follownext_cursor. Never page by offset. See Pagination. - Errors. Standard HTTP status codes plus a typed JSON body with a stable
codeand a humanmessage. See Errors. - Expansion. Related objects appear as IDs by default; add
?expand=decisionto inline them in a single round trip. - Rate limits. Per-token, returned in
RateLimit-*response headers. Back off on429. See Rate limits.
A typed error body looks like this, and the code is safe to branch on in code:
// HTTP 422 Unprocessable Entity { "error": { "code": "amount_below_minimum", "message": "amount_pence must be at least 100000 (£1,000).", "param": "amount_pence", "request_id": "req_2Kd9c5Qm" } }
Quote the request_id when you contact support — it lets us trace the exact call in our logs.
Application lifecycle
An application moves through a defined set of states. Transitions are one-way except where noted, and every transition emits an event — react to those rather than polling.
| State | Meaning | Emits |
|---|---|---|
created | Open; awaiting applicant completion (identity, open banking, principals). | application.created |
submitted | Applicant finished; queued for decisioning. | application.submitted |
in_review | Decisioning is running (or a referral is being underwritten). | — |
approved | Approved; an offer is attached to the decision. | decision.completed |
declined | Declined, with reasons. Terminal. | decision.completed |
funded | Offer accepted and disbursed; an account now exists. | application.funded |
withdrawn / expired | Cancelled by you, or timed out before completion. Terminal. | application.withdrawn |
The happy path is created → submitted → in_review → approved → funded. A referred decision keeps the application in in_review until a human underwriter resolves it, at which point a second decision.completed fires with the final outcome. Because declined, withdrawn and expired are terminal, your state machine never has to handle a resurrected application — start a fresh one instead.
With these concepts in hand, the Quickstart reads in minutes and the API reference is just detail. Model the lifecycle states in your own database from the start — it pays off the moment you handle a referral.
