Settlement
Receive a notification with the full charge list when a settlement is finalized
When a batched settlement is finalized, kamiPay sends a settlement.settled webhook to your configured endpoint. The payload contains the aggregate amounts for the settlement and the full list of charges that were included in it, so you can reconcile each individual charge against your own system without an extra API round-trip. One webhook delivery per scheduled batch summarises the disbursement and lists every charge that was part of it.
This webhook is specific to the batched settlement program. If you are on the legacy 1:1 mode you do not receive settlement.settled — each charge is reconciled individually through the per-charge charge webhook the moment it completes.
settlement.settled
Sent once per settlement when the underlying provider transfer is confirmed and the settlement transitions to DONE.
{
"event": "settlement.settled",
"settlement_id": 12345,
"provider_settlement_id": "psid_8f3c1d2a9e",
"external_settlement_id": "0xa3f9b2c1e7d4865094bd28fa1c3e6b85907df42a3b9c1de80f5a672bc41e9d3f",
"amount": 99325.0,
"currency_id": 32,
"source_amount": 68.5,
"source_currency_id": 9999,
"source_net_price": 68.3,
"settled_at": "2026-05-13T15:00:42Z",
"charges": [
{
"kamipay_id": "txc_01j3t9fxqffrva9s8d1ekm4g3v",
"external_id": "merchant-order-aaa-11112",
"kamipay_request_id": "ptxr_01j3t9fxqffrva9s8d1ekm4g3w",
"charged_amount": 5.28,
"charged_currency": "BRL",
"settlement_amount": 29750.0,
"settlement_currency": "ARS"
},
{
"kamipay_id": "txc_01j4a2x6m1d8h6e5b3t7w1ku9k",
"external_id": "merchant-order-aaa-11113",
"kamipay_request_id": "ptxr_01j4a2x6m1d8h6e5b3t7w1ku9l",
"charged_amount": 7.04,
"charged_currency": "BRL",
"settlement_amount": 39575.0,
"settlement_currency": "ARS"
},
{
"kamipay_id": "txc_01j4c8e7n3p2q5r9w1m6b8y4hj",
"external_id": null,
"kamipay_request_id": "ptxr_01j4c8e7n3p2q5r9w1m6b8y4hk",
"charged_amount": 5.28,
"charged_currency": "BRL",
"settlement_amount": 29750.0,
"settlement_currency": "ARS"
}
]
}Top-level fields
| Field | Type | Description |
|---|---|---|
event | string | Always "settlement.settled". |
settlement_id | integer | Unique identifier of the settlement (matches settlement_id returned by GET /v1/settlements). |
provider_settlement_id | string | null | Provider-side identifier for the transfer. |
external_settlement_id | string | null | Auxiliary external reference (e.g. originating vault transaction hash for off-chain settlements). |
amount | number | Amount actually delivered to your destination address, in currency_id units. |
currency_id | integer | Currency id of amount. |
source_amount | number | Amount kamiPay actually transferred to the provider for this settlement, in source_currency_id units. |
source_currency_id | integer | Currency id of source_amount. |
source_net_price | number | Accumulated value of the included charges on the source side, in source_currency_id units. The difference between source_amount and source_net_price reflects internal repricing absorbed by the settlement. |
settled_at | datetime | ISO 8601 timestamp when the settlement was marked DONE. |
charges | array | All charges included in this settlement. See below. |
charges[] fields
The charges[] array contains one item per charge included in the settlement, ordered by the time each charge was added to the settlement (oldest first).
| Field | Type | Description |
|---|---|---|
kamipay_id | string | The QR/transaction kamiPay identifier of the original charge (matches the value returned at QR creation and the kamipay_id on the corresponding charge webhook). |
external_id | string | null | Your own identifier for the charge, as you supplied it at checkout time. null if you did not provide one. This is the primary reconciliation key for the merchant — the same value appears on the per-charge done event of the charge webhook. |
kamipay_request_id | string | Pay-in request identifier (Pix id). |
charged_amount | number | Amount charged to the payor, typically BRL. |
charged_currency | string | Currency code (alpha3) of charged_amount, e.g. BRL. |
settlement_amount | number | null | The amount the charge was quoted at — the settlement-side promise, expressed in the currency the checkout quotes in. null only for charges with no quote linked. |
settlement_currency | string | null | Currency code (alpha3) of settlement_amount — the quote currency of the checkout quote layout (e.g. ARS, USDt, BRL). |
Reconciliation
The intended flow for merchants:
- As charges complete, you receive a
doneevent on the charge webhook for each one. Match it against your order usingexternal_idand record it as collected. - When the settlement is finalized you receive a single
settlement.settledwebhook. Thecharges[]array carries the sameexternal_idfor every charge you previously recorded. - Use
external_idto match each entry incharges[]back to your collected orders, and useamount(incurrency_idunits) to record the disbursement against your bank/wallet account.
The shape of charges[] exactly mirrors what GET /v1/settlements/{settlement_id} returns. If you ever miss a webhook delivery you can fetch the same data over REST and get the same reconciliation keys.
Signature validation, retries, and ordering
- Signature: every webhook is signed with the same scheme as the charge and pay webhooks. Always validate the signature before processing the payload.
- Idempotency:
settlement_idis the natural idempotency key. kamiPay may retry the delivery (e.g. on a non-2xx response from your endpoint) and you may receive the samesettlement.settledpayload more than once. Treat repeated deliveries with the samesettlement_idas no-ops after the first successful processing. - Ordering:
settlement.settledis fired after all of the per-chargedoneevents for the charges incharges[]. You may, however, receive asettlement.settledfor one settlement before alldoneevents for charges in a different settlement, so do not assume strict cross-settlement ordering. - Delivery channel: this event uses the same webhook endpoint and authentication configuration as your other kamiPay webhooks. No separate configuration is required.
Always validate the webhook signature using the method described in the Introduction before processing any webhook events.