kamiPay LogokamiPay Docs

Settlements

Reconcile incoming Pix charges against the off-chain transfers that delivered the funds to your wallet

Settlements track the transfers that move funds from kamiPay's vault to your destination address after one or more pay-in charges have been collected. Where Lots record the on-chain batches used for pay-outs, settlements record the off-chain disbursements that close a pay-in lifecycle.

In the legacy 1:1 mode, every successful charge produces its own settlement. In the batched settlement program (see below), multiple charges are grouped into a single settlement on a recurring schedule.


Batched Settlement Program

In the batched settlement program, charges are accumulated and grouped into a single settlement on a recurring schedule, replacing the per-charge disbursement flow with one consolidated transfer per cycle.

How it works

  1. As charges complete, each one is marked done and you receive the usual charge webhooks. The charge enters the "pending charges" pool for the next settlement cycle.
  2. On a recurring schedule, kamiPay groups all of your done charges that have no associated settlement into a single settlement.
  3. When the settlement is confirmed, you receive a settlement.settled webhook listing every charge it included (with your external_id per charge).

Behavior for non-enrolled merchants: all settlement endpoints below work for you regardless of mode. In 1:1 mode, the Pending Charges endpoint will always return an empty list because every charge is settled the moment it completes.

To enroll in the batched settlement program, contact your account manager.


Blockchain batched settlements

The batched settlement program runs in two flavours, depending on how a checkout is paid out:

  • Fiwind batched settlement — the original ARS flow. Charges are requoted and disbursed in ARS through the Fiwind provider.
  • Blockchain batched settlement — the same "acknowledge each charge immediately, move the money in one batch" experience, but on the on-chain (USDT) path. Instead of one USDT transfer per charge, the checkout receives one consolidated USDT transfer per settlement window, sent straight to your wallet — fewer on-chain transfers, less gas, cleaner reconciliation.

Blockchain batched settlement is opt-in per checkout. To enable it, contact your account manager.

How it differs from Fiwind batched

  • No FX / no requote. There is no rate math on this path: the transferred amount is the sum of the charges' net prices, in USDt, less any refund deductions. There is no rebalance between what was quoted and what was sent, so with no refunds in play source_amount and source_net_price are equal.
  • Works for all pay-in methods. Static QR, dynamic QR, and payment links are all eligible. Fiwind batched stays ARS-only because it needs an ARS quote to requote, so static-QR charges — which have no quote — cannot use it.
  • Settled in USDt. The consolidated transfer, and the per-charge settlement_amount you see in the API and the settlement.settled webhook, are denominated in USDt rather than ARS.

Lifecycle

  1. Each charge completes and is acknowledged to you immediately — you receive the usual per-charge done charge webhook, but no money moves yet and there is no settlement id or transaction hash attached. The charge enters the pending-charges pool. There is no separate per-charge settlement webhook on this path.
  2. On a recurring schedule, kamiPay sweeps every confirmed-but-unsettled charge for the checkout and sends one bulk USDT transfer to your wallet. The settlement moves to PROCESSING once the transfer is broadcast.
  3. Completion is detected on-chain. There is no provider webhook on this path — kamiPay polls until the bulk transfer is mined, then marks the settlement DONE and fires a single settlement.settled webhook listing every charge it included.

Settlement mode comparison

ARS per-chargeARS batchedBlockchain batched
Groupingone settlement per chargeone settlement per windowone settlement per window
Payout railFiwind (off-chain, ARS)Fiwind (off-chain, ARS)on-chain USDT transfer
Settlement currencyARSARSUSDt
FX / requoteyes (per charge)yes (per batch)none — sum of net prices
Eligible pay-in methodsARS-quoted onlyARS-quoted onlyall (static QR, dynamic QR, links)
Completion signalproviderprovideron-chain (transfer mined)

A checkout can be in at most one settlement mode at a time — the three modes are mutually exclusive. Your account manager configures the mode for you.


Refunds in batched settlements

Pay-in refunds work differently on a checkout enrolled in the batched settlement program, in both flavours. A batched charge never had a transfer of its own — it was paid out as part of a bulk disbursement — so there is nothing to reverse individually. Instead, the refund is deducted from your next settlement.

The practical consequences:

  • No refund wallet, and nothing to pre-fund. The USDT leg is netted out of a future disbursement rather than pulled from a wallet you hold, so the wallet prerequisites described in Refunds do not apply to these checkouts. Refunds are enabled by default on them.
  • The deduction usually lands in a later batch than the charge. It is applied by the first settlement that runs after the refund is confirmed. Expect refunds[] entries that point at orders you reconciled in an earlier cycle.
  • Deductions are prorated at the original charge's own rate, so a full refund cancels its charge exactly.
  • A refund never triggers a settlement. It waits for the next scheduled cycle that has charges.

Where the deduction is visible

SurfaceField
Pending Chargespending_refunds[], plus refund_count / refund_deduction / net_settlement_amount in totals
Get Settlement Detailrefunds[]
settlement.settled webhookrefunds[]

In all three, the charge totals are gross — they do not subtract refunds. The net figure is amount on a settlement, and totals.net_settlement_amount on the pending preview.

If pending refund deductions add up to more than the charges waiting to be settled, no settlement is produced that cycle — a zero or negative transfer makes no sense. Charges and refunds both stay pending and are netted in a later cycle, once new charges have accumulated to absorb the deduction. On the pending preview this shows up as a negative net_settlement_amount.


List Settlements

GET /v1/settlements

List your settlements by settled_at date range. Use this to reconcile completed disbursements with charges and to audit the off-chain transfers that closed them.

Query Parameters

NameTypeDescription
start_datedatetimeRequired. Start of settled_at range. ISO 8601 with a UTC offset (e.g. 2026-05-01T00:00:00Z). A datetime without an offset is rejected with 400.
end_datedatetimeRequired. End of settled_at range. ISO 8601 with a UTC offset (e.g. 2026-05-31T23:59:59Z). A datetime without an offset is rejected with 400.
limitintMaximum results (1–1000). Default: 100.
offsetintPagination offset. Default: 0.

Maximum date range is 31 days. For longer periods, make multiple requests.

Example Request

const params = new URLSearchParams({
  start_date: '2026-05-01T00:00:00Z',
  end_date: '2026-05-28T23:59:59Z',
  limit: '100',
  offset: '0'
});

const url = `${baseURL}/v1/settlements?${params}`;

const response = await fetch(url, {
  method: "GET",
  headers: {
    Authorization: `Bearer ${access_token}`,
    "Content-Type": "application/json",
  },
});
import requests

params = {
    'start_date': '2026-05-01T00:00:00Z',
    'end_date': '2026-05-28T23:59:59Z',
    'limit': 100,
    'offset': 0,
}

url = f"{base_url}/v1/settlements"

headers = {
    'Authorization': f'Bearer {access_token}',
    'Content-Type': 'application/json',
}

response = requests.get(url, params=params, headers=headers)
package main

import (
  "fmt"
  "net/http"
  "net/url"
)

func main() {
  baseURL := "https://api.kamipay.io"
  params := url.Values{}
  params.Add("start_date", "2026-05-01T00:00:00Z")
  params.Add("end_date", "2026-05-28T23:59:59Z")
  params.Add("limit", "100")
  params.Add("offset", "0")

  url := fmt.Sprintf("%s/v1/settlements?%s", baseURL, params.Encode())

  req, _ := http.NewRequest("GET", url, nil)
  req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", access_token))
  req.Header.Add("Content-Type", "application/json")

  client := &http.Client{}
  resp, err := client.Do(req)
  if err != nil {
    fmt.Println("Error:", err)
    return
  }
  defer resp.Body.Close()
}

Response

{
  "settlements": [
    {
      "settlement_id": 12345,
      "settlement_provider_name": "provider_x",
      "provider_settlement_id": "psid_8f3c1d2a9e",
      "external_settlement_id": "0xa3f9b2c1e7d4865094bd28fa1c3e6b85907df42a3b9c1de80f5a672bc41e9d3f",
      "amount": 63400.0,
      "currency": "ARS",
      "address_to": "0x7a3F9b2C1e8D5462bA9c7F3e6D85907df41A2c3B",
      "address_from": "0x4f2D9aB16C3eD7849bA5d3E2F8C19075aE63C9B1",
      "settlement_message": null,
      "settled_at": "2026-05-14T15:00:42Z",
      "created_at": "2026-05-14T14:55:18Z",
      "status": "DONE"
    }
  ],
  "total": 1,
  "limit": 100,
  "offset": 0
}

Date range validation error

{
  "detail": "Date range cannot exceed 31 days"
}

Invalid date order

{
  "detail": "end_date must be after start_date"
}

Missing UTC offset

{
  "detail": "start_date must include a UTC offset (e.g. 2026-05-01T00:00:00Z)"
}
{
  "detail": "Incorrect Credentials"
}

Settlement Fields

FieldTypeDescription
settlement_idintegerUnique identifier of the settlement.
settlement_provider_namestringProvider that executed the transfer.
provider_settlement_idstring | nullProvider-side identifier for the transfer. null until the provider confirms.
external_settlement_idstring | nullAuxiliary external reference (e.g. on-chain transaction hash for blockchain settlements, originating vault tx hash for off-chain settlements).
amountnumberAmount delivered to your address_to, in currency units.
currencystringCurrency code (alpha3) of amount, e.g. ARS.
address_tostringDestination wallet/account where the funds were delivered.
address_fromstringOriginating kamiPay vault address.
settlement_messagestring | nullOptional message attached to the transfer.
settled_atdatetime | nullTimestamp the settlement was confirmed. null while still in flight.
created_atdatetimeSettlement-row creation time.
statusstring | nullCurrent status. See Settlement Status Values.

List Settlement Transactions

GET /v1/settlements/transactions

List the individual charges that have been included in your settlements, with the parent settlement's summary embedded on every row. Use this to drill from a settlement to its constituent charges, or to fetch a flat list of all charge-to-settlement associations in a window.

Query Parameters

NameTypeDescription
start_datedatetimeRequired. Start of the charged_timestamp range — when the pay-in request (QR/charge) was created, the same value returned on each row. ISO 8601 with a UTC offset (e.g. 2026-05-01T00:00:00Z). A datetime without an offset is rejected with 400.
end_datedatetimeRequired. End of the charged_timestamp range. ISO 8601 with a UTC offset. A datetime without an offset is rejected with 400.
settlement_idintegerFilter to a specific settlement id.
limitintMaximum results (1–1000). Default: 100.
offsetintPagination offset. Default: 0.

Maximum date range is 31 days.

Example Request

const params = new URLSearchParams({
  start_date: '2026-05-01T00:00:00Z',
  end_date: '2026-05-28T23:59:59Z',
  settlement_id: '12345',
});

const url = `${baseURL}/v1/settlements/transactions?${params}`;

const response = await fetch(url, {
  method: "GET",
  headers: {
    Authorization: `Bearer ${access_token}`,
    "Content-Type": "application/json",
  },
});
import requests

params = {
    'start_date': '2026-05-01T00:00:00Z',
    'end_date': '2026-05-28T23:59:59Z',
    'settlement_id': 12345,
}

url = f"{base_url}/v1/settlements/transactions"
headers = {
    'Authorization': f'Bearer {access_token}',
    'Content-Type': 'application/json',
}

response = requests.get(url, params=params, headers=headers)
params := url.Values{}
params.Add("start_date", "2026-05-01T00:00:00Z")
params.Add("end_date", "2026-05-28T23:59:59Z")
params.Add("settlement_id", "12345")

u := fmt.Sprintf("%s/v1/settlements/transactions?%s", baseURL, params.Encode())
req, _ := http.NewRequest("GET", u, nil)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", access_token))

Response

{
  "transactions": [
    {
      "settlement_id": 12345,
      "kamipay_request_id": "ptxr_01kr3m9p7n2s4d8h6e5b3t7w1k",
      "kamipay_id": "dqr_01kr3m9q5h7w2v4n6b8s3d5e9p",
      "external_id": "merchant-order-aaa-11112",
      "charged_amount": 5.28,
      "charged_currency": "BRL",
      "settlement_amount": 29750.0,
      "settlement_currency": "ARS",
      "charged_timestamp": "2026-05-14T13:21:08Z",
      "received_timestamp": "2026-05-14T13:23:11Z",
      "settlement_provider_name": "provider_x",
      "settled_at": "2026-05-14T15:00:42Z",
      "provider_settlement_id": "psid_8f3c1d2a9e",
      "external_settlement_id": "0xa3f9b2c1e7d4865094bd28fa1c3e6b85907df42a3b9c1de80f5a672bc41e9d3f"
    }
  ],
  "total": 1,
  "limit": 100,
  "offset": 0
}

Date range validation error

{
  "detail": "Date range cannot exceed 31 days"
}

Missing UTC offset

{
  "detail": "end_date must include a UTC offset (e.g. 2026-05-01T00:00:00Z)"
}
{
  "detail": "Incorrect Credentials"
}

Transaction Fields

FieldTypeDescription
settlement_idintegerParent settlement id.
kamipay_request_idstringPay-in request identifier (Pix id).
kamipay_idstringThe QR/transaction kamiPay identifier (matches the value returned at QR creation).
external_idstring | nullYour own identifier for the charge, as supplied at checkout time. null if you did not provide one. This is the same value emitted on the per-charge done webhook. Use it as your primary reconciliation key.
charged_amountnumberAmount charged to the payor, typically BRL.
charged_currencystringCurrency code (alpha3) of charged_amount, e.g. BRL.
settlement_amountnumber | nullThe 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_currencystring | nullCurrency code (alpha3) of settlement_amount — the quote currency of the checkout quote layout (e.g. ARS, USDt, BRL).
charged_timestampdatetime | nullWhen the pay-in request (QR/charge) was created. This is the field the start_date/end_date window filters and orders on.
received_timestampdatetime | nullWhen the payment was received (the charge was confirmed and began processing). null if no processing transition was recorded.
settlement_provider_namestringProvider of the parent settlement.
settled_atdatetime | nullSettled-at timestamp of the parent settlement. null while in flight.
provider_settlement_idstring | nullProvider-side identifier of the parent settlement.
external_settlement_idstring | nullAuxiliary external reference of the parent settlement.

The charge core (charged_*, settlement_*, charged_timestamp) is the same shape the Pending Charges endpoint returns, so you can relate a settled transaction back to what you previously saw in the pending pool — the transactions endpoint adds the parent-settlement fields and received_timestamp on top.


Pending Charges

GET /v1/settlements/pending-charges

List the charges that are in done status but have not yet been associated with a settlement, for a single checkout. This is the canonical "what would the next settlement for this checkout pick up?" view.

The preview is per-checkout because the sweep settles one settlement per enrolled checkout, not one per merchant.

checkout_id is optional and resolves automatically:

  • If your client has exactly one checkout enrolled in the batched settlement program, you can omit checkout_id — it is resolved for you.
  • If your client has more than one enrolled checkout, checkout_id is required; omitting it returns 400.
  • If your client has no enrolled checkout (or is on the legacy 1:1 flow), the list is always empty — the sweep never settles it, so there is nothing to preview.

Query Parameters

NameTypeDescription
checkout_idintOptional. Checkout to preview. Omit it when your client has a single enrolled checkout (resolved automatically); required when it has more than one.
fromdatetimeOptional. Start of the request created_at window. ISO 8601 with a UTC offset; a datetime without an offset is rejected with 400. Default: now − 30 days (the sweep's eligibility window).
todatetimeOptional. End of the request created_at window. ISO 8601 with a UTC offset; a datetime without an offset is rejected with 400. Default: now.
limitintMaximum items per page (1–500). Default: 100.
offsetintPagination offset. Default: 0.

Example Request

const params = new URLSearchParams({
  checkout_id: '42', // optional when the client has a single enrolled checkout
  from: '2026-04-14T00:00:00Z',
  limit: '100',
  offset: '0',
});

const url = `${baseURL}/v1/settlements/pending-charges?${params}`;

const response = await fetch(url, {
  method: "GET",
  headers: {
    Authorization: `Bearer ${access_token}`,
    "Content-Type": "application/json",
  },
});
import requests

params = {
    'checkout_id': 42,  # optional when the client has a single enrolled checkout
    'from': '2026-04-14T00:00:00Z',
    'limit': 100,
    'offset': 0,
}

url = f"{base_url}/v1/settlements/pending-charges"
headers = {
    'Authorization': f'Bearer {access_token}',
    'Content-Type': 'application/json',
}

response = requests.get(url, params=params, headers=headers)
params := url.Values{}
params.Add("checkout_id", "42") // optional when the client has a single enrolled checkout
params.Add("from", "2026-04-14T00:00:00Z")
params.Add("limit", "100")
params.Add("offset", "0")

u := fmt.Sprintf("%s/v1/settlements/pending-charges?%s", baseURL, params.Encode())
req, _ := http.NewRequest("GET", u, nil)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", access_token))

Response

{
  "items": [
    {
      "kamipay_request_id": "ptxr_01kr3m9p7n2s4d8h6e5b3t7w1k",
      "kamipay_id": "dqr_01kr3m9q5h7w2v4n6b8s3d5e9p",
      "external_id": "merchant-order-aaa-11112",
      "charged_amount": 5.28,
      "charged_currency": "BRL",
      "settlement_amount": 29750.0,
      "settlement_currency": "ARS",
      "charged_timestamp": "2026-05-14T13:21:08Z"
    },
    {
      "kamipay_request_id": "ptxr_01kr4a2x6m1d8h6e5b3t7w1ku",
      "kamipay_id": "dqr_01kr4a2y9n3s7v4n6b8s3d5e9q",
      "external_id": "merchant-order-aaa-11113",
      "charged_amount": 7.04,
      "charged_currency": "BRL",
      "settlement_amount": 39575.0,
      "settlement_currency": "ARS",
      "charged_timestamp": "2026-05-14T14:02:55Z"
    }
  ],
  "pending_refunds": [
    {
      "kamipay_refund_id": "rpi_5b7c2d4e6a8f0b1c3d5e7f90",
      "pay_in_refund_request_id": "rpir_9e7f2fc2c0b14a8d9a1e3f5b7c2d4e6a",
      "kamipay_id": "dqr_01kr3m9q5h7w2v4n6b8s3d5e9p",
      "external_id": "merchant-order-aaa-11112",
      "kamipay_request_id": "ptxr_01kr3m9p7n2s4d8h6e5b3t7w1k",
      "refunded_amount": 1.05,
      "refunded_currency": "BRL",
      "deduction_amount": 5925.0,
      "deduction_currency": "ARS"
    }
  ],
  "totals": {
    "count": 2,
    "settlement_amount": 69325.0,
    "refund_count": 1,
    "refund_deduction": 5925.0,
    "net_settlement_amount": 63400.0
  },
  "limit": 100,
  "offset": 0
}
{
  "items": [],
  "pending_refunds": [],
  "totals": {
    "count": 0,
    "settlement_amount": 0,
    "refund_count": 0,
    "refund_deduction": 0,
    "net_settlement_amount": 0
  },
  "limit": 100,
  "offset": 0
}

checkout_id required (client has more than one enrolled checkout)

{
  "detail": "checkout_id is required: this client has multiple checkouts enrolled in batched settlement"
}

Missing UTC offset

{
  "detail": "from must include a UTC offset (e.g. 2026-05-01T00:00:00Z)"
}

Date range validation error

{
  "detail": "Date range cannot exceed 31 days"
}
{
  "detail": "Incorrect Credentials"
}

Item Fields

Items are ordered by charged_timestamp ascending (oldest pending charge first). The item shape is the same charge core the Settlement Transactions endpoint returns (minus the parent-settlement fields), so you can relate a pending charge to the transaction that eventually settles it.

FieldTypeDescription
kamipay_request_idstringPay-in request identifier.
kamipay_idstringQR/transaction identifier.
external_idstring | nullYour own identifier for the charge, as supplied at checkout time. null if you did not provide one. This is the same value emitted on the per-charge done webhook. Use it as your primary reconciliation key.
charged_amountnumberAmount charged to the payor, typically BRL.
charged_currencystringCurrency code (alpha3) of charged_amount, e.g. BRL.
settlement_amountnumberThe amount the next batched settlement will disburse for this charge. For Fiwind batched checkouts this is the ARS quote; for blockchain batched checkouts it is the charge's net price in USDt.
settlement_currencystringCurrency code (alpha3) of settlement_amountARS for Fiwind batched checkouts, USDt for blockchain batched checkouts.
charged_timestampdatetimeWhen the pay-in request (QR/charge) was created.

pending_refunds[] Fields

The refund deductions the next settlement will net out. Always present; an empty array when there are none. Unlike items, this array is not paged — there is at most one entry per refunded charge, so it is returned whole.

FieldTypeDescription
kamipay_refund_idstringIdentifier of the refund (rpi_…).
pay_in_refund_request_idstring | nullIdentifier of the refund request (rpir_…) as returned by POST /v2/pay_in_refunds/request.
kamipay_idstringQR/transaction identifier of the original charge being refunded.
external_idstring | nullYour own identifier for that original charge. Your reconciliation key.
kamipay_request_idstringPay-in request identifier of the original charge.
refunded_amountnumberAmount returned to the payor, typically BRL.
refunded_currencystringCurrency code (alpha3) of refunded_amount.
deduction_amountnumberAmount that will be subtracted from the settlement, in the same currency as the charges' settlement_amount.
deduction_currencystring | nullCurrency code (alpha3) of deduction_amountARS for Fiwind batched, USDt for blockchain batched.

Totals Block

Totals are computed across the entire filtered set, not just the current page.

FieldTypeDescription
countintegerNumber of pending charges in the filtered set.
settlement_amountnumberGross sum of settlement_amount across the filtered set. Does not subtract pending refunds — this keeps it consistent with source_net_price on the settlement.settled webhook.
refund_countintegerNumber of pending refund deductions.
refund_deductionnumberSum of deduction_amount across pending_refunds.
net_settlement_amountnumberWhat you will actually receive: settlement_amount - refund_deduction. A negative value means no settlement will run this cycle — see Refunds in batched settlements.

Totals reflect the full filtered set (not just the current page), so you can gauge the size of the upcoming settlement without paging through every item.


Get Settlement Detail

GET /v1/settlements/{settlement_id}

Return one settlement with its per-charge breakdown (charges[]). The charges[] shape matches the batched-program settlement.settled webhook contract, so if you ever miss a webhook delivery you can fetch the same data over REST. This endpoint works for any settlement (batched or legacy 1:1) regardless of whether a webhook was sent.

Path Parameters

NameTypeDescription
settlement_idintegerRequired. The settlement_id of the settlement.

Query Parameters

NameTypeDescription

Example Request

const settlement_id = 12345;

const url = `${baseURL}/v1/settlements/${settlement_id}`;

const response = await fetch(url, {
  method: "GET",
  headers: {
    Authorization: `Bearer ${access_token}`,
    "Content-Type": "application/json",
  },
});
import requests

settlement_id = 12345

url = f"{base_url}/v1/settlements/{settlement_id}"
headers = {
    'Authorization': f'Bearer {access_token}',
    'Content-Type': 'application/json',
}

response = requests.get(url, headers=headers)
settlementID := 12345

u := fmt.Sprintf("%s/v1/settlements/%d", baseURL, settlementID)
req, _ := http.NewRequest("GET", u, nil)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", access_token))

Response

{
  "settlement_id": 12345,
  "settlement_provider_name": "provider_x",
  "provider_settlement_id": "psid_8f3c1d2a9e",
  "external_settlement_id": "0xa3f9b2c1e7d4865094bd28fa1c3e6b85907df42a3b9c1de80f5a672bc41e9d3f",
  "amount": 63400.0,
  "currency": "ARS",
  "address_to": "0x7a3F9b2C1e8D5462bA9c7F3e6D85907df41A2c3B",
  "address_from": "0x4f2D9aB16C3eD7849bA5d3E2F8C19075aE63C9B1",
  "settlement_message": null,
  "settled_at": "2026-05-14T15:00:42Z",
  "created_at": "2026-05-14T14:55:18Z",
  "status": "DONE",
  "charges": [
    {
      "kamipay_id": "dqr_01kr3m9q5h7w2v4n6b8s3d5e9p",
      "external_id": "merchant-order-aaa-11112",
      "kamipay_request_id": "ptxr_01kr3m9p7n2s4d8h6e5b3t7w1k",
      "charged_amount": 5.28,
      "charged_currency": "BRL",
      "settlement_amount": 29750.0,
      "settlement_currency": "ARS",
      "charged_timestamp": "2026-05-14T13:21:08Z",
      "received_timestamp": "2026-05-14T13:23:11Z"
    },
    {
      "kamipay_id": "dqr_01kr4a2y9n3s7v4n6b8s3d5e9q",
      "external_id": "merchant-order-aaa-11113",
      "kamipay_request_id": "ptxr_01kr4a2x6m1d8h6e5b3t7w1ku",
      "charged_amount": 7.04,
      "charged_currency": "BRL",
      "settlement_amount": 39575.0,
      "settlement_currency": "ARS",
      "charged_timestamp": "2026-05-14T14:02:55Z",
      "received_timestamp": "2026-05-14T14:05:13Z"
    }
  ],
  "refunds": [
    {
      "kamipay_refund_id": "rpi_5b7c2d4e6a8f0b1c3d5e7f90",
      "pay_in_refund_request_id": "rpir_9e7f2fc2c0b14a8d9a1e3f5b7c2d4e6a",
      "kamipay_id": "dqr_01kr3m9q5h7w2v4n6b8s3d5e9p",
      "external_id": "merchant-order-aaa-11112",
      "kamipay_request_id": "ptxr_01kr3m9p7n2s4d8h6e5b3t7w1k",
      "refunded_amount": 1.05,
      "refunded_currency": "BRL",
      "deduction_amount": 5925.0,
      "deduction_currency": "ARS",
      "created_at": "2026-05-14T14:55:18Z"
    }
  ]
}
{
  "detail": "Incorrect Credentials"
}

Returned when the settlement does not exist or belongs to another merchant.

{
  "detail": "Settlement not found"
}

Detail Fields

The top-level fields are the same as a settlement row from GET /v1/settlements, plus charges and refunds arrays.

FieldTypeDescription
chargesarrayAll charges included in this settlement.
refundsarrayRefund deductions applied to this settlement. Always present; an empty array when none. amount is net of these — without them the gap between amount and the sum of charges[] is unexplained.

In the example above the two charges add up to 69,325 ARS, the refund deducts 5,925, and amount is the resulting 63,400 — what actually reached the destination address.

charges[] Fields

FieldTypeDescription
kamipay_idstringThe QR/transaction kamiPay identifier of the original charge.
external_idstring | nullYour own identifier for the charge, as supplied at checkout time. null if you did not provide one. Use it as your primary reconciliation key.
kamipay_request_idstringPay-in request identifier (Pix id).
charged_amountnumberAmount charged to the payor, typically BRL.
charged_currencystringCurrency code (alpha3) of charged_amount, e.g. BRL.
settlement_amountnumber | nullThe 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_currencystring | nullCurrency code (alpha3) of settlement_amount — the quote currency of the checkout quote layout (e.g. ARS, USDt, BRL).
charged_timestampdatetime | nullWhen the pay-in request (QR/charge) was created.
received_timestampdatetime | nullWhen the payment was received (the charge was confirmed and began processing). null if no processing transition was recorded.

refunds[] Fields

FieldTypeDescription
kamipay_refund_idstringIdentifier of the refund (rpi_…).
pay_in_refund_request_idstring | nullIdentifier of the refund request (rpir_…) returned by POST /v2/pay_in_refunds/request.
kamipay_idstringQR/transaction identifier of the original charge being refunded. Often settled by an earlier settlement than this one.
external_idstring | nullYour own identifier for that original charge. Use it as your reconciliation key.
kamipay_request_idstring | nullPay-in request identifier of the original charge.
refunded_amountnumberAmount returned to the payor, typically BRL.
refunded_currencystring | nullCurrency code (alpha3) of refunded_amount.
deduction_amountnumberAmount subtracted from this settlement, in the settlement's own currency.
deduction_currencystring | nullCurrency code (alpha3) of deduction_amount.
created_atdatetimeWhen the deduction was attached to this settlement.

Settlement Status Values

StatusDescription
CREATEDSettlement record created; the outbound transfer has not yet been issued.
PROCESSINGOutbound transfer issued; waiting for the provider to confirm.
DONEProvider confirmed the transfer; funds are with the merchant.
CANCELEDSettlement was cancelled before completion (typically because the underlying transfer was not attempted).
FAILEDOutbound transfer or provider confirmation failed irrecoverably. Manual ops resolution.

Use Cases

Daily reconciliation

  1. GET /v1/settlements for the day's settled_at range.
  2. For each settlement, capture settlement_id, amount, currency, and settled_at for your books.
  3. GET /v1/settlements/{settlement_id} (or GET /v1/settlements/transactions?settlement_id=<id>) to enumerate the charges included in each settlement. Each charge carries your external_id — use it to match charges back to your own records — plus charged_timestamp (when the QR/charge was created) and received_timestamp (when the payment was received) for a per-charge timeline.
  4. Read refunds[] on the same response. Those amounts were subtracted from amount, so a settlement whose charges do not add up to amount is explained here. The refunded charges usually belong to an earlier settlement.

Previewing the pending pool

If you are enrolled in the batched settlement program and want to know which charges are currently queued for the next run:

  1. GET /v1/settlements/pending-charges — with a single enrolled checkout you can omit checkout_id; with more than one, pass ?checkout_id=<c> (one call per checkout, since the sweep settles per checkout).
  2. Read totals.count for the number of charges in that checkout's pool and totals.settlement_amount for the expected disbursement of its next settlement.
  3. Iterate items[] (paging with limit/offset) for per-charge details; match each item's external_id to your own records.

On this page