> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cadanapay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Transaction Reconciliation

> Reconcile payroll, payouts, and wallet transactions across all businesses on your platform

export const ApiExample = ({method = "GET", path, params, body, reference, tenantKey}) => {
  const baseUrl = "https://api.cadanapay.com";
  const query = params ? "?" + Object.entries(params).map(([k, v]) => `${k}=${v}`).join("&") : "";
  const url = `${baseUrl}${path}${query}`;
  const isPlatformPath = (/^\/(v1\/)?platform(\/|$)/).test(path || "");
  const includeTenantKey = tenantKey === undefined ? !isPlatformPath : tenantKey;
  let curl = `curl -X ${method} '${url}' \\\n  -H 'Authorization: Bearer YOUR_API_KEY'`;
  if (includeTenantKey) {
    curl += ` \\\n  -H 'X-MultiTenantKey: YOUR_BUSINESS_TENANT_KEY'`;
  }
  if (body) {
    const formatted = JSON.stringify(body, null, 2);
    curl += ` \\\n  -H 'Content-Type: application/json' \\\n  -d '${formatted}'`;
  }
  return <div>
      <CodeBlock language="bash" filename="bash" wrap>
        {curl}
      </CodeBlock>
      {reference && <div style={{
    marginTop: "-0.5rem",
    marginBottom: "1rem"
  }}>
          <a href={reference} style={{
    fontSize: "0.875rem"
  }}>
            Try it in the playground →
          </a>
        </div>}
    </div>;
};

The **Platform Disbursements** endpoint gives platform partners a unified view of all transactions across every business under your platform — payroll payments, payouts, and other financial operations — in a single query. Use it to build reconciliation reports, track revenue share, drill into payroll fee breakdowns via invoices, and reconcile your books.

```mermaid theme={null}
flowchart LR
    A[Fetch disbursements] --> B[Group by tenantKey]
    B --> C[Per-business ledger]
    C --> D[Payroll: group by referenceId]
    C --> E[Wallet: group by userId]
    D --> F[Drill into invoice for fee breakdown]
```

***

## Prerequisites

<Steps>
  <Step title="API key from Dashboard">
    Get your API key from the [Cadana Dashboard](https://app.cadanapay.com). See [Authentication](/authentication) for details.
  </Step>

  <Step title="Platform integration">
    You must be set up as a platform partner managing multiple businesses. See [Platform Overview](/platform/overview).
  </Step>

  <Step title="Businesses with transactions">
    At least one business under your platform must have completed payroll runs or wallet transactions.
  </Step>
</Steps>

***

## Platform Disbursements

Fetch all transactions across every business on your platform. Results are filtered by date range and paginated automatically.

<ApiExample
  method="GET"
  path="/v1/platform/disbursements"
  params={{
startDate: "2026-01-01",
endDate: "2026-02-01",
status: "SUCCESS",
type: "PAYROLL,PAYOUT,CARD_MAINTENANCE_FEE,CARD_CREATION_FEE,STOCK_BUY,STOCK_SELL,PAYROLL_FEE,INTEREST"
}}
  reference="/api-reference/workforce/platform/list-disbursements"
/>

### Query Parameters

| Parameter             | Type          | Required | Description                                                                                                               |
| :-------------------- | :------------ | :------- | :------------------------------------------------------------------------------------------------------------------------ |
| `businessId`          | string (uuid) | No       | Scope results to a single business account (see [Scope to a Single Business](#scope-to-a-single-business)).               |
| `currency`            | string        | No       | Filter by the business-facing currency — matches either the destination `amount` or the `sourceAmount` (e.g. `USD`).      |
| `startDate`           | string        | No       | Start of date range (ISO 8601, e.g. `2026-01-01`). Defaults to 7 days ago.                                                |
| `endDate`             | string        | No       | End of date range (ISO 8601, e.g. `2026-02-01`). Defaults to now.                                                         |
| `type`                | string        | No       | Comma-separated transaction types to include (see [Transaction Types](#transaction-types)).                               |
| `status`              | string        | No       | Filter by status: `SUCCESS`, `FAILED`, `INITIATED`, `PROCESSING`, `ROUTED`.                                               |
| `includeRevenueShare` | boolean       | No       | Set to `true` to include the revenue-share fields in each item (see [Revenue Share](#revenue-share)). Omitted by default. |

### Response Structure

```json theme={null}
{
  "data": [ ... ],
  "cursor": {
    "previous": null,
    "next": "eyJsYXN0S2V5Ijp7InBrIjoiLi4uIn19"
  }
}
```

### Transaction Object Fields

| Field                  | Type   | Description                                                                                                                    |
| :--------------------- | :----- | :----------------------------------------------------------------------------------------------------------------------------- |
| `id`                   | string | Unique transaction identifier                                                                                                  |
| `tenantKey`            | string | Identifies which business this transaction belongs to. Use this to group transactions per business.                            |
| `status`               | string | Transaction status: `SUCCESS`, `FAILED`, `INITIATED`, `PROCESSING`, `ROUTED`                                                   |
| `referenceId`          | string | External reference. Payroll transactions from the same run share the same `referenceId`.                                       |
| `description`          | string | Human-readable description (e.g. "January 2026 Payment Dundies")                                                               |
| `type`                 | string | Transaction type (see [Transaction Types](#transaction-types))                                                                 |
| `fxRate`               | number | FX rate applied. Present only for cross-currency transactions.                                                                 |
| `paymentMethod`        | string | Delivery method: `bank`, `momo`, `wallet`, `ach`, `card`, `proxy`                                                              |
| `paymentDetails`       | object | Full payment method details (bank account, mobile money, wallet, ACH, card info)                                               |
| `personId`             | string | Employee or contractor ID. **Present only on payroll transactions.**                                                           |
| `userId`               | string | Wallet/user account ID. Present on wallet-based transactions. For payroll, only present when payment is delivered to a wallet. |
| `userName`             | string | Recipient name                                                                                                                 |
| `amount`               | object | Amount the recipient receives, in the **destination currency**                                                                 |
| `sourceAmount`         | object | Cost in the **source currency**, before fees                                                                                   |
| `feeAmount`            | object | Fees charged, in the source currency                                                                                           |
| `totalAmount`          | object | Total debited from sender: `sourceAmount` + `feeAmount`                                                                        |
| `fxRevenueShare`       | object | Revenue earned from FX spread (see [Revenue Share](#revenue-share))                                                            |
| `feeRevenueShare`      | object | Revenue earned from fees (see [Revenue Share](#revenue-share))                                                                 |
| `totalRevenueShare`    | object | Combined total revenue share                                                                                                   |
| `createdTimestamp`     | string | When the transaction was created                                                                                               |
| `lastUpdatedTimestamp` | string | When the transaction was last updated                                                                                          |

All amount fields follow this structure:

```json theme={null}
{
  "value": "100.00",
  "currency": "USD"
}
```

***

## Transaction Types

| Type                   | Description                                                                                                                                                 |
| :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PAYROLL`              | Payment from a business to an employee or contractor as part of a payroll run                                                                               |
| `PAYOUT`               | Outbound transfer from a user's wallet to an external bank, mobile money, card, or other destination                                                        |
| `TRANSFER`             | Internal movement of funds between your platform's own business accounts — the main parent and its children (see [Internal Transfers](#internal-transfers)) |
| `PAYROLL_FEE`          | Processing fee for a payroll run (see [Payroll Fee & Invoice Details](#payroll-fee--invoice-details))                                                       |
| `CARD_MAINTENANCE_FEE` | Recurring maintenance fee for a virtual card                                                                                                                |
| `CARD_CREATION_FEE`    | One-time fee for creating a virtual card                                                                                                                    |
| `STOCK_BUY`            | Stock purchase transaction                                                                                                                                  |
| `STOCK_SELL`           | Stock sale transaction                                                                                                                                      |
| `INTEREST`             | Interest earned or charged                                                                                                                                  |

***

## Internal Transfers

Move money between your own business accounts — your main business and any of its child businesses — with the [Create Transfer](/api-reference/workforce/platform/create-transfer) endpoint. Transfers are internal, same-currency only, and settle immediately with no fee. Name the `sourceTenantKey` (optional — omit to send from your main business) and `destinationTenantKey` in the request body; allowed movements are main → child, child → child, and child → main.

<ApiExample
  method="POST"
  path="/v1/platform/transfers"
  body={{
sourceTenantKey: "blm123456",
destinationTenantKey: "blm998877",
amount: { amount: 500000, currency: "USD" },
reference: "transfer-123"
}}
  reference="/api-reference/workforce/platform/create-transfer"
/>

Create Transfer returns only the transfer `id` — there's no `GET` for it. Find a transfer here by filtering to `type=TRANSFER` (or scope to one account with `businessId`), then match the returned `id` or your `reference`. It appears under the **source** business as an outgoing transaction.

<ApiExample
  method="GET"
  path="/v1/platform/disbursements"
  params={{
startDate: "2026-01-01",
endDate: "2026-02-01",
type: "TRANSFER"
}}
  reference="/api-reference/workforce/platform/list-disbursements"
/>

***

## Identifying Businesses with tenantKey

Every transaction includes a `tenantKey` that identifies which business it belongs to. Group by `tenantKey` to produce per-business reconciliation reports.

```json theme={null}
[
  { "id": "...", "tenantKey": "tbl28153208", "type": "PAYROLL" },
  { "id": "...", "tenantKey": "tbl89195039", "type": "PAYROLL" },
  { "id": "...", "tenantKey": "cad35916961", "type": "PAYOUT" }
]
```

***

## Scope to a Single Business

Pass `businessId=<uuid>` to narrow the list to one business's account. This returns every disbursement where that business's account is the **sender or recipient** — both money it **sent** (payroll, vendor payments, payouts) and money it **received** (deposits, refunds/reversals). It is bidirectional.

This is distinct from `tenantKey`: `tenantKey` returns everything under a tenant, while `businessId` returns only the rows touching that one business's account — a narrower set.

<ApiExample
  method="GET"
  path="/v1/platform/disbursements"
  params={{
businessId: "1e6c5a83-7b86-4a32-a7da-0e5e2b3d8f10",
currency: "USD",
startDate: "2026-04-09",
endDate: "2026-06-09",
limit: 50
}}
  reference="/api-reference/workforce/platform/list-disbursements"
/>

The response shape, fields, and ordering (newest-first by `createdTimestamp`) are identical to the unfiltered call. A few things to keep in mind when reading the items:

* **Direction comes from `type`**, not a dedicated field. For example, `DEPOSIT` is inbound; `PAYROLL_TOTAL` and `VENDOR` are outbound. Don't assume a fixed direction for every type.
* **`userId` / `userName` are the counterparty** (the other side of the transaction), not the scoped business itself — so an item is not necessarily "a payment the business sent to `userId`".
* By default the per-employee `PAYROLL` legs and `PAYROLL_FEE` rows are collapsed into the single `PAYROLL_TOTAL` line; pass an explicit `type` to get the raw rows. Business-relevant types include `PAYROLL_TOTAL`, `PAYROLL`, `PAYROLL_FEE`, `PAYROLL_REVERSAL`, `DEPOSIT`, `DEPOSIT_REVERSAL`, `VENDOR`, `REVENUE_SHARE_PAYOUT`, `REIMBURSEMENT`, `SUBSCRIPTION_PAYMENT`, and `STATUTORY_DEPOSIT`.

### Paging through a business's disbursements

Pagination is the same as the unfiltered endpoint: read `cursor.next` from each response and send it back to fetch the next page, repeating until it comes back `null` (default `limit` 50, max 100). The cursor is opaque — don't parse it.

```
GET /v1/platform/disbursements?businessId=…&currency=USD&limit=50
  → cursor.next = "eyJsYXN0S2V5Ijp…"
GET /v1/platform/disbursements?businessId=…&currency=USD&limit=50&next=eyJsYXN0S2V5Ijp…
  → cursor.next = null   (done)
```

***

## Payroll Transactions

Payroll transactions (`type: "PAYROLL"`) represent individual payments to employees or contractors. Key identifiers:

* **`personId`** — the employee or contractor being paid. Always present on payroll transactions and is the primary identifier for reconciliation.
* **`userId`** — only present when payment is delivered to a **wallet**. Not present for external payments (bank, mobile money, etc.).
* **`referenceId`** — shared across all payments in the same payroll run, so you can group them.
* **`description`** — contains the name of the payroll run (e.g. "January 2026 Payment Dundies").

**Example — cross-currency payroll payment to a bank account:**

```json theme={null}
{
  "id": "a2f47c91-3b8e-4d12-9c6a-7e5d1f8b2a40",
  "tenantKey": "tbl89195039",
  "status": "SUCCESS",
  "referenceId": "9c4829a8-0177-4dad-a0d8-e4f8fc42276a",
  "description": "January 2026 Payment Dundies",
  "type": "PAYROLL",
  "fxRate": 5.812,
  "paymentMethod": "bank",
  "personId": "0a938505-ae3f-44a2-9793-196a4a11e6f2",
  "userName": "Maria Santos",
  "amount": { "value": "5812.00", "currency": "BRL" },
  "sourceAmount": { "value": "1000.00", "currency": "USD" },
  "totalAmount": { "value": "1000.00", "currency": "USD" },
  "fxRevenueShare": { "amount": { "value": "10.00", "currency": "USD" }, "rate": 1 },
  "totalRevenueShare": { "value": "10.00", "currency": "USD" }
}
```

<Note>
  `userId` is absent here because the payment was delivered to an external bank account, not a wallet.
</Note>

**Example — same-currency payroll payment via wallet:**

```json theme={null}
{
  "id": "c6250a16-eb63-41de-a952-8122d305ebbf",
  "tenantKey": "tbl12101631",
  "status": "SUCCESS",
  "referenceId": "7b82d74e-4ad5-4fbf-af9c-a0f11b224c7a",
  "description": "January 2026 Payment PS",
  "type": "PAYROLL",
  "paymentMethod": "wallet",
  "userId": "060e3aeb-4a9d-4a90-aff5-17f8d69635ce",
  "personId": "8ab2ba37-3c37-485d-9af9-122d11c96bf9",
  "userName": "Reed Maygone",
  "amount": { "value": "1000.00", "currency": "USD" },
  "sourceAmount": { "value": "1000.00", "currency": "USD" },
  "totalAmount": { "value": "1000.00", "currency": "USD" }
}
```

Here `userId` is present because the payment went to the employee's wallet. Same-currency payroll has no `fxRate` or FX revenue share, and may not have fee fields since fees are captured in the payroll fee transaction instead.

***

## Wallet Transactions

Transactions of type `PAYOUT`, `CARD_MAINTENANCE_FEE`, `CARD_CREATION_FEE`, `STOCK_BUY`, `STOCK_SELL`, and `INTEREST` are wallet-level operations. They are associated with a user via the `userId` field.

<Note>
  These transactions may include revenue share fields depending on your platform agreement.
</Note>

**Example — cross-currency payout to a bank account in Brazil:**

```json theme={null}
{
  "id": "c5bcdbba-52a2-44a4-8dda-2b03d47a1af1",
  "tenantKey": "tbl28153208",
  "status": "SUCCESS",
  "type": "PAYOUT",
  "fxRate": 5.7896,
  "paymentMethod": "bank",
  "userId": "8cb1d569-5dfd-4b33-b25e-4fab0ee14251",
  "userName": "Paula Torres",
  "amount": { "value": "578.96", "currency": "BRL" },
  "sourceAmount": { "value": "100.00", "currency": "USD" },
  "feeAmount": { "value": "13.50", "currency": "USD" },
  "totalAmount": { "value": "113.50", "currency": "USD" },
  "fxRevenueShare": { "amount": { "value": "1.00", "currency": "USD" }, "rate": 1 },
  "feeRevenueShare": { "amount": { "value": "10.00", "currency": "USD" } },
  "totalRevenueShare": { "value": "11.00", "currency": "USD" }
}
```

***

## Understanding Amounts

Each transaction has four amount fields that tell you the full financial picture:

| Field          | Description                                                  |
| :------------- | :----------------------------------------------------------- |
| `amount`       | What the **recipient receives**, in the destination currency |
| `sourceAmount` | Cost in the **sender's currency**, before fees               |
| `feeAmount`    | Fees charged, in the sender's currency                       |
| `totalAmount`  | Total debited from sender: `sourceAmount` + `feeAmount`      |

### Cross-Currency Example

When a user sends USD and the recipient receives BRL:

```
sourceAmount:  100.00 USD   (cost before fees)
feeAmount:      13.50 USD   (fees)
totalAmount:   113.50 USD   (total debited = 100.00 + 13.50)
fxRate:        5.7896        (USD → BRL conversion rate)
amount:        578.96 BRL    (what the recipient gets: 100.00 × 5.7896)
```

### Same-Currency Example

When both sides are in the same currency, no FX conversion applies:

```
sourceAmount:  1000.00 USD
feeAmount:        0.00 USD
totalAmount:   1000.00 USD
amount:        1000.00 USD   (same as source, no conversion)
```

***

## Revenue Share

If your platform has a revenue share agreement with Cadana, eligible transactions include revenue share fields showing your earnings. These fields are **only present when applicable** — they are omitted when no revenue share applies.

| Field               | Description                                                                                            |
| :------------------ | :----------------------------------------------------------------------------------------------------- |
| `fxRevenueShare`    | Revenue earned from the FX spread. Contains `amount` (value + currency) and `rate` (share percentage). |
| `feeRevenueShare`   | Revenue earned from transaction fees. Contains `amount` (value + currency).                            |
| `totalRevenueShare` | Combined total of FX and fee revenue share. Contains `value` and `currency`.                           |

**Example — transaction with both FX and fee revenue share:**

```json theme={null}
{
  "fxRevenueShare": {
    "amount": { "value": "0.41", "currency": "USD" },
    "rate": 1
  },
  "feeRevenueShare": {
    "amount": { "value": "10.07", "currency": "USD" }
  },
  "totalRevenueShare": { "value": "10.48", "currency": "USD" }
}
```

In this case, the platform earned \$0.41 from the FX spread and \$10.07 from fees, totaling \$10.48 in revenue share.

<Tip>
  Sum `totalRevenueShare` across all transactions to determine your platform's total earnings for a period. Break it down further with `fxRevenueShare` and `feeRevenueShare` to understand the source of revenue.
</Tip>

***

## Payroll Fee & Invoice Details

When a business runs payroll, a separate `PAYROLL_FEE` transaction appears representing the processing fee for the entire run. To see the **detailed breakdown** of how the fee was calculated (per-employee line items), you need the invoice ID.

### Getting the Invoice ID

After a payroll completes, the [payroll response](/api-reference/workforce/payrolls/get) includes an `invoiceId` field. Fetch the payroll by its ID (you can find this via the `referenceId` on any `PAYROLL` transaction from the disbursements response):

<ApiExample method="GET" path="/v1/payrolls/9c4829a8-0177-4dad-a0d8-e4f8fc42276a" reference="/api-reference/workforce/payrolls/get" />

The response includes the `invoiceId` once the payroll is in `completed` status. Then use that ID to fetch the full invoice:

<ApiExample method="GET" path="/v1/invoices/8dbaa174-b5a0-4396-8c87-77e746b50917" reference="/api-reference/workforce/invoices/get-invoice" />

The invoice provides a full breakdown of charges associated with a payroll run, including per-employee costs, FX markups, and fees.

To download the invoice as a PDF:

<ApiExample method="GET" path="/v1/invoices/8dbaa174-b5a0-4396-8c87-77e746b50917/url" reference="/api-reference/workforce/invoices/get-invoice-url" />

**Response:**

```json theme={null}
{
  "fileUrl": "https://...",
  "expiresAt": 1710590400
}
```

<Note>
  The `fileUrl` is short-lived. Fetch a new URL each time you need to download the PDF.
</Note>

***

## Pagination

Results are paginated. The `cursor` object tells you whether more pages are available:

```json theme={null}
{
  "cursor": {
    "previous": null,
    "next": "eyJsYXN0S2V5Ijp7InBrIjoiLi4uIn19"
  }
}
```

* **`cursor.next`** — pass as the `cursor` query parameter to fetch the next page
* **`cursor.previous`** — pass to go back to the previous page
* **`null`** — no more pages in that direction

**Fetching the next page:**

<ApiExample
  method="GET"
  path="/v1/platform/disbursements"
  params={{
startDate: "2026-01-01",
endDate: "2026-02-01",
status: "SUCCESS",
cursor: "eyJsYXN0S2V5Ijp7InBrIjoiLi4uIn19"
}}
/>

***

## Reconciliation Walkthrough

### Step 1: Fetch all successful transactions for the period

<ApiExample
  method="GET"
  path="/v1/platform/disbursements"
  params={{
startDate: "2026-01-01",
endDate: "2026-02-01",
status: "SUCCESS",
type: "PAYROLL,PAYOUT,CARD_MAINTENANCE_FEE,CARD_CREATION_FEE,STOCK_BUY,STOCK_SELL,PAYROLL_FEE,INTEREST"
}}
  reference="/api-reference/workforce/platform/list-disbursements"
/>

Paginate through all results using the `cursor.next` value until it returns `null`.

### Step 2: Group by business

Group transactions by `tenantKey` to build per-business ledgers:

| tenantKey     | Transaction Count | Total Debited  |
| :------------ | :---------------- | :------------- |
| `tbl28153208` | 15                | \$627.47 USD   |
| `tbl89195039` | 2                 | \$385.00 USD   |
| `tbl12101631` | 2                 | \$3,000.00 USD |
| `cad35916961` | 6                 | \$103.55 USD   |

### Step 3: For payroll, identify employees by personId

Filter for `type: "PAYROLL"` and group by `personId` to see how much each employee was paid:

| personId       | Employee Name    | Total Paid (destination) | tenantKey     |
| :------------- | :--------------- | :----------------------- | :------------ |
| `0a938505-...` | Elizabeth Wilson | 151.39 GHS               | `tbl89195039` |
| `00b39f7a-...` | Dwight Schrute   | 5,677.18 GHS             | `tbl89195039` |
| `8ab2ba37-...` | Reed Maygone     | 1,000.00 USD             | `tbl12101631` |
| `ca49c55b-...` | Mahatra Ghandi   | 2,000.00 USD             | `tbl12101631` |

### Step 4: Calculate revenue share

Sum `totalRevenueShare` across all transactions for your platform's total earnings. Break down further with `fxRevenueShare` and `feeRevenueShare`.

### Step 5: Get payroll fee details

For any `PAYROLL_FEE` transactions, use the [Get Invoice](/api-reference/workforce/invoices/get-invoice) endpoint to retrieve the detailed breakdown, including per-employee line items.

***

## Account Statements

Download a formatted **account statement** for a business over a date range with the [Get Business Statement](/api-reference/workforce/businesses/get-business-statement) endpoint. The statement bundles the opening and closing balance, period totals, and every transaction line into a single document — ready to hand to accounting or reconcile against your books.

Pick the output with the `format` query parameter:

| `format`    | Returns               |
| :---------- | :-------------------- |
| *(omitted)* | JSON statement object |
| `csv`       | CSV file download     |
| `bai2`      | BAI2 file download    |

<ApiExample
  method="GET"
  path="/v1/businesses/{businessId}/statement"
  params={{
currency: "USD",
periodStart: "2026-01-01",
periodEnd: "2026-01-31",
format: "csv"
}}
  reference="/api-reference/workforce/businesses/get-business-statement"
/>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Pay Workers via Payroll" icon="money-check-dollar" href="/workforce/pay-workers-via-payroll">
    Run payroll to generate the transactions you'll reconcile
  </Card>

  <Card title="Payroll Lifecycle" icon="arrows-spin" href="/workforce/payroll-lifecycle">
    Understand payroll statuses and when invoices become available
  </Card>

  <Card title="Fund Your Account" icon="building-columns" href="/fund-your-account">
    Ensure your business accounts are funded before running payroll
  </Card>

  <Card title="Webhooks" icon="bell" href="/reference/webhooks">
    Get real-time notifications for transaction events
  </Card>
</CardGroup>
