Partners
Markdown

List a customer’s payouts

GET /api/v1/partner/customers/{customerId}/payouts

Required scope: payouts:read. Capability: payouts.

Newest first. Merges two legs onto one timeline: forecast rows (status: "upcoming", not yet run) and history rows (every payout that has already been executed). A read of this endpoint is exempt from the merchant-eligibility gate — a lapsed KYB grace does not take a merchant’s own settlement history offline for the partner that most needs it to reconcile.

curl "https://www.niftipay.com/api/v1/partner/customers/pc-1/payouts?limit=25" \
  -H "Authorization: Bearer <partner_api_key>"

Response 200

{
  "request_id": "req-1",
  "api_version": "2026-08-01",
  "data": {
    "payouts": [
      {
        "id": "upcoming_usr_a1b2c3d4_2026-10-15_EUR",
        "status": "upcoming",
        "currency": "EUR",
        "net_cents": 128900,
        "net_eur_cents": 128900,
        "payout_due_at": "2026-10-15T00:00:00.000Z",
        "paid_at": null,
        "created_at": "2026-10-01T00:00:03.000Z",
        "orders_count": 14
      },
      {
        "id": "7d1dcdd4-9f3a-4c21-8f0e-2b1c9a5d4e10",
        "status": "paid",
        "currency": "EUR",
        "net_cents": 483210,
        "net_eur_cents": 483210,
        "payout_due_at": "2026-09-30T00:00:00.000Z",
        "paid_at": "2026-09-30T08:12:44.000Z",
        "created_at": "2026-09-23T00:00:05.000Z",
        "orders_count": 0
      }
    ],
    "next_cursor": "MjAyNi0xMC0xNVQwMDowMDowMC4wMDBafHVwY29taW5nX3Vzcl9hMWIyYzNkNF8yMDI2LTEwLTE1X0VVUg"
  }
}

An empty list is 200 with [], never 404. The customer exists — “no payouts yet” is a fact about the collection, not a missing resource.

Query parameters

Parameter Notes
?limit= Defaults to 25, caps at 100. Out-of-range is clamped, not rejected — an oversized page size has one obvious correct reading, so it should not fail a partner merely tuning it.
?before= The next_cursor from a previous response. Opaque — treat it as a token, not a value to construct.
?status= One of upcoming, pending, paid, failed, cancelled, processing. Unlike limit, an out-of-range value is rejected with 400 invalid_request, not clamped or ignored: a typo’d status has no obvious correct reading, and silently answering with the unfiltered list would let a partner reconcile against a set it believes is narrower than it actually is.

Paging

next_cursor is issued only on a full page. A short page is the end of the list, so it comes back null. A full page that happens to be the last one gets a cursor whose next fetch is an empty page — that is the loop’s ordinary termination.

The cursor is a keyset over (payout_due_at, id), base64url-encoded and opaque. Do not construct one yourself — a hand-built cursor that isn’t exactly what this API issued comes back 400 invalid_cursor.

while cursor is not null:
    page = GET /customers/{id}/payouts?limit=100&before=<cursor>
    cursor = page.data.next_cursor

orders_count is 0 on every settled (non-upcoming) row. The underlying payout record has no such column — the real count lives inside the payout’s calculation JSON, and parsing that JSON per row on a list is exactly the cost this endpoint exists to avoid. Fetch the payout by id to get the real orders_count and the per-order array. Forecast (upcoming) rows are unaffected and always carry their real count.

What a payout covers

A payout is the merchant’s entire settlement for the period — not just the business this partner originated. A payout is computed against the merchant’s whole account: their direct sales, orders placed through this partner, and orders placed through any other partner the merchant also works with, all summed against one retention hold and one fee total for that period.

So the amounts on this list (and the full breakdown on the detail read) can be, and often will be, larger than the sum of orders this partner itself created for that merchant. There is no way to filter a payout down to “this partner’s share” — the money was never split that way in the first place. If a specific merchant should not be readable this way, the partner’s payouts capability on that relationship can be revoked; the payout itself cannot be narrowed.

Errors

Status code Meaning
400 invalid_cursor before is not a cursor this API issued.
400 invalid_request status is not one of the recognised values.
403 insufficient_scope Token was not minted with payouts:read.
403 capability_not_enabled payouts is off for this customer.
404 resource_not_found Not your customer, or the relationship was revoked.
503 temporarily_unavailable Read failed transiently; retry shortly.
500 internal_error Unknown failure. Not an invitation to retry.