Payments API
Move money against a funded account — one-off payment links, recurring collection schedules and ad-hoc repayments — then reconcile every movement through signed payment.* webhooks. Collections settle over open banking (PISP) so you never touch card or bank credentials.
Roadmap — not yet available. These endpoints do not exist yet and return 503 Service Unavailable. Documentation is provided so you can design against the planned shape. Build against the live token + MCP surface today; availability will be announced on the changelog.
The Payments API drives the money-in side of servicing: a borrower repaying their facility, an early settlement, or a scheduled instalment plan that mirrors the loan's repayment terms. Money-out (disbursement of approved funds) is handled separately and is not exposed on the partner ring. Every resource lives under the partner/v1 base URL and is authenticated with a bearer token.
- Base URL
https://hub.credicorp.co.uk/partner/v1- Auth
- OAuth 2.0 bearer token — scope
payments:writefor creation,payments:readfor retrieval. - Rails
- Open banking payment initiation (PISP) for collections; Faster Payments settlement.
- Idempotency
- Required on every write — send a unique
Idempotency-Keyheader.
Amounts are integers in pence. A repayment of £500.00 is amount_pence: 50000. Currency is always GBP. Never send a decimal — the API rejects non-integer amounts.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| POST | /payments/links | Create a hosted payment link for a one-off repayment. |
| POST | /payments/schedules | Create a recurring collection schedule against a mandate. |
| GET | /payments/{id} | Retrieve a single payment. |
| GET | /payments | List payments (filter by account_id, status). |
| GET | /payments/schedules/{id} | Retrieve a schedule and its upcoming collections. |
| POST | /payments/{id}/refund | Reverse a settled payment. |
| DEL | /payments/schedules/{id} | Cancel an open-ended schedule (tombstoned, not destroyed). |
Create a payment link
A payment link returns a hosted pay.credicorp.co.uk URL you can email, SMS or embed. The borrower selects their bank, authenticates in their banking app, and the payment settles by Faster Payments. You receive a payment.paid webhook on settlement.
curl -s https://hub.credicorp.co.uk/partner/v1/payments/links \ -H "Authorization: Bearer $TOKEN" \ -H "Idempotency-Key: pl_3f9a1c" \ -H "Content-Type: application/json" \ -d '{ "account_id": "acc_2WdR7yK", "amount_pence": 50000, "reference": "INV-2026-0481", "description": "June instalment", "redirect_url": "https://app.acme.co.uk/repay/done" }'
import Credicorp from '@credicorp/sdk'; const cc = new Credicorp({ token: process.env.CC_TOKEN }); const link = await cc.payments.links.create({ account_id: 'acc_2WdR7yK', amount_pence: 50000, reference: 'INV-2026-0481', description: 'June instalment', redirect_url: 'https://app.acme.co.uk/repay/done' }, { idempotencyKey: 'pl_3f9a1c' }); console.log(link.url); // → https://pay.credicorp.co.uk/l/9Lm…
use Credicorp\Client; $cc = new Client(token: getenv('CC_TOKEN')); $link = $cc->payments->links->create([ 'account_id' => 'acc_2WdR7yK', 'amount_pence' => 50000, 'reference' => 'INV-2026-0481', 'description' => 'June instalment', ], idempotencyKey: 'pl_3f9a1c'); echo $link->url;
Parameters
| Field | Type | Description | |
|---|---|---|---|
account_id | string | req | Funded account the repayment is applied to. |
amount_pence | integer | req | Amount to collect, in pence. Must be > 0. |
reference | string | opt | Your reference (≤18 chars). Echoed on the bank statement and every webhook. |
description | string | opt | Shown to the payer on the hosted page. |
redirect_url | string | opt | Where the payer returns after authorising. Falls back to your dashboard default. |
expires_at | string | opt | RFC 3339 expiry. Default 7 days. |
Response 201 Created
{
"id": "pay_9Lm4Qx",
"object": "payment",
"account_id": "acc_2WdR7yK",
"status": "pending",
"amount_pence": 50000,
"currency": "GBP",
"reference": "INV-2026-0481",
"url": "https://pay.credicorp.co.uk/l/9Lm4Qx",
"expires_at": "2026-07-06T11:04:00Z",
"created_at": "2026-06-29T11:04:00Z"
}Create a collection schedule
A schedule sets up recurring collections — typically the repayment plan agreed at origination — against a payment mandate held on the account. Each due date generates a child payment which is initiated automatically; you are notified per instalment by payment.paid or payment.failed.
curl -s https://hub.credicorp.co.uk/partner/v1/payments/schedules \ -H "Authorization: Bearer $TOKEN" \ -H "Idempotency-Key: sch_88c0" \ -d '{ "account_id": "acc_2WdR7yK", "amount_pence": 41667, "cadence": "monthly", "start_date": "2026-07-15", "count": 12, "mandate_id": "mnd_7Hb2" }'
Parameters
| Field | Type | Description | |
|---|---|---|---|
account_id | string | req | Funded account to collect against. |
amount_pence | integer | req | Per-instalment amount. |
cadence | string | req | weekly or monthly. |
start_date | string | req | First collection date (RFC 3339 date). |
count | integer | opt | Number of instalments. Omit for open-ended. |
mandate_id | string | opt | Existing mandate. If absent, the first collection establishes one. |
Response 201 Created
{
"id": "sch_5Tk9Pa",
"object": "payment_schedule",
"account_id": "acc_2WdR7yK",
"status": "active",
"cadence": "monthly",
"amount_pence": 41667,
"remaining": 12,
"next_collection": {
"payment_id": "pay_A1c…",
"due_date": "2026-07-15"
}
}Match the plan, not the calendar. Derive amount_pence and count from the account's repayment schedule (see Accounts roadmap) so collections stay in lock-step with the outstanding balance. A final “sweep” instalment squares any rounding remainder.
Payment statuses
A payment moves through a small, deterministic lifecycle. Drive your ledger from webhooks rather than polling — statuses are terminal once reached, except paid → refunded.
| Status | Webhook | Meaning |
|---|---|---|
pending | — | Created; payer has not yet authorised, or the due date has not arrived. |
processing | payment.processing | Authorised and submitted to Faster Payments; awaiting settlement. |
paid | payment.paid | Settled and applied to the account balance. |
failed | payment.failed | Bounced, cancelled or expired. See failure_reason. |
refunded | payment.refunded | A settled payment was reversed in full. |
Failure reasons
| Code | Description |
|---|---|
insufficient_funds | Payer's account lacked the balance. |
payer_cancelled | Authorisation abandoned or declined in-app. |
mandate_revoked | The collection mandate was withdrawn. |
link_expired | Hosted link reached expires_at unpaid. |
bank_unavailable | The payer's bank could not be reached; safe to retry. |
Refund a payment
Reverses a settled payment over the same rails. Only full refunds are supported; the resulting credit is applied back to the account and a payment.refunded event is emitted.
curl -s -X POST https://hub.credicorp.co.uk/partner/v1/payments/pay_9Lm4Qx/refund \ -H "Authorization: Bearer $TOKEN" \ -H "Idempotency-Key: rf_001" \ -d '{ "reason": "duplicate_collection" }'
Reconciliation
Every state change is delivered as a signed webhook, so your ledger never has to poll. Subscribe to the payment.* family and match each event to your records using the account_id plus your own reference. Events are HMAC-signed and retried with exponential back-off — verify the signature and de-duplicate on event.id.
{
"id": "evt_Qm0v2",
"type": "payment.paid",
"created_at": "2026-06-29T11:09:42Z",
"data": {
"id": "pay_9Lm4Qx",
"account_id": "acc_2WdR7yK",
"reference": "INV-2026-0481",
"amount_pence": 50000,
"status": "paid",
"settled_at": "2026-06-29T11:09:40Z"
}
}| Event | Fires when |
|---|---|
payment.processing | Payer authorised; submitted to the rails. |
payment.paid | Funds settled and applied to the account. |
payment.failed | Collection bounced, expired or was cancelled. |
payment.refunded | A settled payment was reversed. |
schedule.completed | The final instalment of a fixed schedule settled. |
Treat webhooks as the source of truth, never the redirect. A payer returning to your redirect_url does not guarantee settlement — funds may still be processing. Only mark a repayment cleared on payment.paid. See Webhooks roadmap for signature verification and the full retry policy.
Errors
All errors from this endpoint use the standard hub error envelope. Branch on code for precise handling; quote correlation_id when contacting support.
{
"error": {
"code": "validation_failed",
"message": "The request failed validation.",
"detail": [{ "field": "amount_pence", "reason": "min_value" }],
"correlation_id": "cor_01J2K3M4N5P6Q7R8S9T0A1V2W3",
"retryable": false
}
}| code | HTTP | When |
|---|---|---|
validation_failed | 422 | A required field is missing or a value is out of range. detail[] carries per-field specifics. |
conflict | 409 | Idempotency-Key reused with a different body, or illegal state transition. |
not_found | 404 | No account or payment found for the supplied ID. |
unauthenticated | 401 | Missing or invalid access token. |
token_expired | 401 | Token has expired — refresh it and retry. |
insufficient_scope | 403 | Token not granted payments:write (creation) or payments:read (retrieval). |
rate_limited | 429 | Request rate over the quota; honour retry_after_ms and Retry-After. See Rate limits. |
internal_error | 500 | Unexpected fault on our side. Safe to retry idempotent calls with back-off; quote correlation_id to support. |
service_unavailable | 503 | Temporary maintenance or overload. Retry with back-off; check status. |
The full error code list and all envelope fields are on the Errors page.
Related: Accounts roadmap for balances and repayment schedules, Webhooks roadmap for signed delivery, and Idempotency for safe retries.
