Pagination
All list endpoints — applications, payments, accounts, events — return a uniform, cursor-paginated envelope. Walk it with limit and the cursor parameters starting_after / ending_before. Cursors are stable object IDs, so iteration stays correct even as new records arrive.
REST list endpoints are on the roadmap. The /partner/v1/payments, /partner/v1/accounts and other list routes used in the examples below are not yet live — they return 503 Service Unavailable. This page documents the pagination contract so you can design ahead. The live partner surface today is the token + MCP endpoint only; list-endpoint availability will be announced on the changelog.
Credicorp uses cursor pagination, not page numbers. Cursors are immune to the "shifting window" problem of offsets: inserting a record while you page through doesn't skip or duplicate rows. Every list across the API — from applications to events — behaves identically.
The list envelope
A list response is an object with object: "list", the page in data (newest first), and a has_more flag. The url echoes the resource path.
{
"object": "list",
"url": "/partner/v1/applications",
"has_more": true,
"data": [
{ "id": "app_8Kd2c9Qm", "object": "application", "status": "funded" },
{ "id": "app_7Jc1bY6n", "object": "application", "status": "approved" },
{ "id": "app_6Hb0aX5m", "object": "application", "status": "in_review" }
]
}| Field | Type | Description |
|---|---|---|
object | string | Always "list" for a paginated response. |
data | array | This page of objects, ordered newest first by creation time. |
has_more | boolean | true if more records exist after this page. Stop when it is false. |
url | string | The path that produced the list, for convenience. |
There is no total_count field. Counting every row would be slow and racy on large datasets — rely on has_more and stop when it's false.
Query parameters
These parameters are accepted by every list endpoint. starting_after and ending_before are mutually exclusive.
| Parameter | Type | Description | |
|---|---|---|---|
limit | integer | opt | Page size, 1–100. Defaults to 20. |
starting_after | string | opt | An object ID. Returns the page of results immediately after it — used to page forward (toward older records). |
ending_before | string | opt | An object ID. Returns the page immediately before it — used to page backward (toward newer records). |
Endpoint-specific filters — such as status, created_after or reference on applications — compose freely with the pagination parameters and persist across pages.
Paging forward
To walk the whole collection, take the id of the last object in data and pass it as starting_after on the next call. Repeat while has_more is true.
# Page 1 — newest 20 curl -s "https://hub.credicorp.co.uk/partner/v1/payments?limit=20" \ -H "Authorization: Bearer $TOKEN" # Page 2 — start after the last id from page 1 curl -s "https://hub.credicorp.co.uk/partner/v1/payments?limit=20&starting_after=pay_5Gd9cQ2v" \ -H "Authorization: Bearer $TOKEN"
Auto-pagination in the SDKs
Every SDK wraps the cursor loop. Use the iterator helpers to stream an entire collection without managing cursors by hand — they fetch the next page lazily as you consume the current one.
// autoPagingIterator transparently fetches each page $payments = $cc->payments->all(['limit' => 100, 'status' => 'settled']); foreach ($payments->autoPagingIterator() as $payment) { reconcile($payment->id, $payment->amount_pence); }
// async iterator pages automatically for await (const payment of cc.payments.list({ limit: 100, status: 'settled' })) { await reconcile(payment.id, payment.amount_pence); }
# auto_paging_iter yields every object across pages for payment in cc.payments.list(limit=100, status="settled").auto_paging_iter(): reconcile(payment.id, payment.amount_pence)
Paging by hand
If you manage the cursor yourself, the loop is short. Hold the last ID, stop on has_more === false:
let cursor = null, all = []; do { const qs = new URLSearchParams({ limit: '100' }); if (cursor) qs.set('starting_after', cursor); const res = await fetch(`https://hub.credicorp.co.uk/partner/v1/accounts?${qs}`, { headers: { Authorization: `Bearer ${TOKEN}` } }); const page = await res.json(); all.push(...page.data); cursor = page.has_more ? page.data[page.data.length - 1].id : null; } while (cursor);
Iterating safely
- Drive the loop with
has_more, notdata.length. A short page does not mean the end — onlyhas_more: falsedoes. - Cursors are object IDs, not opaque tokens. Persist the last ID to resume a long export later from exactly where you stopped.
- Use the largest sensible
limit(up to 100) to cut round-trips and stay clear of rate limits; pace bulk pulls and honourRetry-Afteron 429. - Records added mid-iteration are safe. Because cursors anchor to a specific ID, a new application created while you page forward simply appears at the head of the list and won't disrupt your walk toward older records.
- For ongoing sync, prefer webhooks. Page once for the historical backfill, then keep state current from events rather than re-scanning the list.
A starting_after or ending_before cursor must reference an ID of the same resource type as the list. Passing an ID from another collection returns 404 with code not_found — see Errors.
