For the complete documentation index, see llms.txt. This page is also available as Markdown.

Settlement Reconciliation Patterns

Settlement Reconciliation Patterns

This page explains how to reconcile settlement activity across a full merchant portfolio efficiently, as a scheduled job rather than a loop that runs once per merchant. It also covers the timestamp, status field, and pagination details that most often trip up reconciliation jobs.

Use Settlement data and deposit reconciliation if you need the field level reference for tracing one deposit back to one settlement. Use this page if you're building a recurring job that reconciles many merchants at once.

When to use this page

Use these patterns when you need to:

  • Run a nightly or scheduled reconciliation job across many merchants under a partner.

  • Detect settlement status changes incrementally, without pulling everything again each cycle.

  • Decide which status or amount field is authoritative when more than one looks relevant.

  • Understand why a payment record doesn't reflect a settlement event you know happened.

  • Avoid unnecessary per merchant API calls in a reconciliation loop.

The pattern: pull once for the portfolio, not once per merchant

GET /Settlements accepts a MerchantIds array. If you serve multiple merchants under a partner, pass all of their merchant IDs in a single call rather than looping per merchant:

GET /Settlements?From=2026-07-15&To=2026-07-16&MerchantIds=mer_1&MerchantIds=mer_2&MerchantIds=mer_3

This returns settlement records for every merchant in the list in one paginated response. The same bulk filtering approach applies to Batches, which accepts both MerchantIds and SettlementIds arrays. Building your reconciliation job around list calls with array filters, rather than one call per merchant per entity, is the single biggest efficiency gain available today.

Detecting settlement changes incrementally

Don't use a payment's updated timestamp to detect settlement events. Assigning a settlement to a payment does not change the payment record. Payments and settlements are separate entities, and this is expected behavior, not a bug. A payment can leave your sync window (if you're windowing on payment updated) before it's ever assigned to a settlement, and you'll never see that assignment on the payment side.

Detect changes on the settlement record instead. Two facts about the settlement record's timestamps determine how you do this correctly:

  • GET /Settlements returns both created and updated on every settlement record, and updated is reliably bumped on every settlement state change (cleared, hold, dispatched, paid). So updated is a sound change signal.

  • From and To filter on the settlement's created date, not updated. They return settlements created in the window. updated is sortable (SortBy=updated) but is not range filterable today: there is no updatedFrom / updatedTo or ModifiedSince parameter.

Because the change signal (updated) and the filter axis (created) are different fields, From/To on its own is not an updated-since feed. A settlement created before your window that changes state inside it (for example cleared to paid several days after it was created, which is exactly the change you're polling for) is excluded, because it was filtered out on created. Don't window on From/To alone and assume you have caught every change.

Use this two part pattern instead:

  1. Discovery of new settlements. Call GET /Settlements with your MerchantIds and a From/To window covering the period since your last sync, adding SortBy=updated&SortDirection=desc. This surfaces settlements created since you last ran, most recently changed first.

  2. Correctness for slow state changes. Maintain a working set of the settlement IDs you have seen that are not yet in a terminal state (status not paid). Each run, re-fetch GET /Settlements/{id} for those tracked IDs and compare updated (or status) against what you last stored. Drop an ID from the set once it reaches paid. Reading a settlement by ID is not affected by the created window, so this catches a transition no matter how long after creation it happens.

This bounds your work to new settlements plus the settlements you are still tracking, independent of total history, and does not miss a slow transition such as a settlement sitting in hold for several days before it clears.

If you want the simplest possible version, widen From to cover the full period in which a settlement can still change state and re-fetch that whole window each run, deduping on updated versus your last sync on your side. This is fine for normal timing, but a settlement can remain in hold longer than any fixed window, so pair the widened window with the ID tracking in step 2 for anything not yet paid.

Two similarly named fields that are not the same thing

Field
Lives on
Values
What it actually means

paymentSettlementStatusCode

Payment (Reporting APIs)

created, pending, processing, completed, error, initiationFailed

Whether this payment's own settlement record has been created and processed internally.

status

Settlement record

cleared, hold, dispatched, paid

Where the settlement itself is in the funding and payout lifecycle.

These describe different state machines. A payment can show paymentSettlementStatusCode of completed while its settlement is still status of hold. That's not a contradiction. It just means the payment's own settlement record finished processing before the settlement itself finished funding. Don't infer funding or payout state from paymentSettlementStatusCode, and don't infer payment level settlement processing from settlement status.

Settled amount: which field is authoritative

Use the settlement record's netFundableAmount as the settled amount for a merchant or period. Don't use the payment's settleableAmount as your reconciled total. It reflects a single payment's settleable amount at the payment level, not the actual net amount funded after batch level fees, deposit fees, and adjustments (chargebacks, holdbacks, and so on) are applied. The settlement record is the only place those are all rolled up together. See Settlements for the full net fundable amount formula.

Known limitation: you can't filter the payments list by settlement or batch

The merchant, partner, and terminal payments endpoints do not support filtering by settlementId or batchId directly. If you need the payments behind a specific settlement or batch, go the other direction:

  • GET /Settlements/{id}/batches to get the batches in a settlement.

  • Read paymentIds off each batch.

  • Cross reference those IDs against your own payment records, or look them up individually.

Don't build a reconciliation loop that assumes you can query payments by settlementId. That filter doesn't exist today.

Pagination: zero based across the board

Pagination is zero based across every paged endpoint referenced on this page. page (or Page) equals 0 returns the first page in the Reporting family (Partner, Merchant, and Terminal Payments) and in the Settlement family (Settlements, Batches). There is one shared convention, not two.

If you previously read guidance here suggesting the Reporting family defaults to page equals 1, that was inaccurate and has been corrected. Confirmed directly against the live Pagination and Sorting reference, the Settlements endpoint reference, and the Batches endpoint reference.

Typical integration flow: nightly portfolio reconciliation

Goal: reconcile settlement activity for every merchant under a partner, once per night, without per merchant calls.

  1. Track your last successful sync timestamp, and keep a working set of settlement IDs you have seen that are not yet paid.

  2. Discovery call: GET /Settlements with MerchantIds set to your full merchant list and From/To covering the window since last sync, SortBy=updated&SortDirection=desc. Remember From/To filter on created, so this finds newly created settlements. Add any new non-terminal settlement IDs to your working set.

  3. Change detection: re-fetch GET /Settlements/{id} for each ID in your working set and treat a changed updated or status as a change to process. This catches transitions on settlements created before the current window. Drop an ID from the set once its status is paid.

  4. If you need batch level detail for a changed settlement, call GET /Settlements/{id}/batches.

  5. If you need transaction level detail, use paymentIds from each batch to cross reference your own records.

  6. Use netFundableAmount from the settlement record as your reconciled total for that merchant or period.

  7. Advance your last sync timestamp only after the run completes successfully.

Next steps

Last updated