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

# Payouts

> Trigger, confirm, list, export, and manage payouts via /sdk/v1.

All endpoints below require:

* `X-Application-Id`
* `X-Api-Key`

## POST /sdk/v1/payouts/trigger

Create a single payout. Supports immediate execution or returning a pending confirmation token.

<Info>
  This endpoint does not calculate campaign contract terms or tiered bonus templates. To configure reusable campaign bonuses, use `/sdk/v1/bonus-templates`, apply the returned `templateId` to a campaign contract, and let Grade calculate eligible bonus line items from tracked campaign media.
</Info>

### Headers

* `X-Idempotency-Key` (required)

### Body

You must provide:

* `payoutRecipientEmail` (required; must be a valid email)
* `payoutCurrency` (required; one of `USD`, `CAD`, `GBP`, `EUR`)
* exactly one of:
  * `payoutAmount` (positive; max 2 decimals)
  * `lineItems` (array; each item requires `quantity` and `perItemAmount`)
* `requireConfirmation` (optional; defaults to `true`)
* `returnPayoutLink` (optional boolean; when `true`, successful executed payout responses include `payout_link`)
* `platformFeePayerOverride` (optional; one of `INHERIT`, `CREATOR_PAYS_ALL`, `AGENCY_PAYS_ALL`, `CUSTOM_SPLIT`)
* `platformFeeAgencySharePercent` (required when `platformFeePayerOverride` is `CUSTOM_SPLIT`; number between `0` and `100`)

```json theme={null}
{
  "payoutRecipientEmail": "creator@example.com",
  "payoutCurrency": "USD",
  "requireConfirmation": true,
  "lineItems": [
    { "lineItemDescription": "Instagram post", "quantity": 1, "perItemAmount": "150.00" },
    { "lineItemDescription": "Story set", "quantity": 2, "perItemAmount": "25.00" }
  ]
}
```

If you need to override who covers the platform fee for this payout only, send:

```json theme={null}
{
  "payoutRecipientEmail": "creator@example.com",
  "payoutCurrency": "USD",
  "payoutAmount": "200.00",
  "platformFeePayerOverride": "CUSTOM_SPLIT",
  "platformFeeAgencySharePercent": 40
}
```

Omit `platformFeePayerOverride`, or set it to `INHERIT`, to use the agency default. The returned `preview.platformFee` values reflect the effective override.

Set `returnPayoutLink` to `true` when you need the payout link in the execution response. Pending trigger responses do not include a link because the payout has not been executed yet; the confirmed payout response includes `payout_link` if the original trigger requested it. If the link cannot be resolved at response time after a successful payout, `payout_link` is `null`.

### Response

* If `requireConfirmation: true`: `201`

```json theme={null}
{
  "success": true,
  "pending_payout_id": "pnd_...",
  "preview": {
    "payoutRecipientEmail": "creator@example.com",
    "payoutCurrency": "USD",
    "payoutAmount": 200,
    "lineItems": [
      { "lineItemDescription": "Instagram post", "quantity": 1, "perItemAmount": 150, "lineTotal": 150 },
      { "lineItemDescription": "Story set", "quantity": 2, "perItemAmount": 25, "lineTotal": 50 }
    ],
    "creatorCurrency": "USD",
    "amountInCreatorCurrency": 200,
    "platformFee": {
      "displayCurrency": "USD",
      "feeTotalDisplayAmount": 0,
      "feePaidByCreatorDisplayAmount": 0,
      "feePaidByAgencyDisplayAmount": 0,
      "netDisplayAmount": 200
    }
  },
  "expiresAt": "2026-02-19T00:00:00.000Z"
}
```

* If `requireConfirmation: false`: `200` (example includes `payout_link` when `returnPayoutLink` is `true`)

```json theme={null}
{
  "success": true,
  "payoutId": "pay_...",
  "invoiceId": "inv_...",
  "currency": "USD",
  "amount": 200,
  "email": "creator@example.com",
  "payout_link": "https://payout.example/..."
}
```

### Common errors

* `400`: invalid payload (missing fields, currency not supported, >2 decimals, etc.)
* `400`: insufficient funds (includes `sufficient: false`, `requiredAmount`, `currency: "USD"`)
* `401`: missing/invalid SDK headers
* `403`: origin not allowed (when allowlist is configured and `Origin` is present)

## POST /sdk/v1/payouts/trigger-bulk

Create up to 100 payouts in one request.

### Headers

* `X-Idempotency-Key` (required)

### Body

`payouts` must be a non-empty array, max length 100. Each item is the same shape as `POST /payouts/trigger`.

All items must share the same `requireConfirmation` value.
Each item can set its own `platformFeePayerOverride` and `platformFeeAgencySharePercent`.

```json theme={null}
{
  "payouts": [
    {
      "payoutRecipientEmail": "creator1@example.com",
      "payoutCurrency": "USD",
      "requireConfirmation": true,
      "payoutAmount": "10.00"
    },
    {
      "payoutRecipientEmail": "creator2@example.com",
      "payoutCurrency": "USD",
      "requireConfirmation": true,
      "payoutAmount": "15.00"
    }
  ]
}
```

### Response

* If `requireConfirmation: true`: `201`

```json theme={null}
{
  "success": true,
  "requireConfirmation": true,
  "results": [
    {
      "index": 0,
      "pending_payout_id": "pnd_...",
      "preview": { "payoutRecipientEmail": "creator1@example.com", "payoutCurrency": "USD", "payoutAmount": 10 },
      "expiresAt": "2026-02-19T00:00:00.000Z"
    }
  ]
}
```

* If `requireConfirmation: false`: `200` (example includes `payout_link` when an item sets `returnPayoutLink` to `true`)

```json theme={null}
{
  "success": true,
  "requireConfirmation": false,
  "results": [
    {
      "index": 0,
      "success": true,
      "payoutId": "pay_...",
      "invoiceId": "inv_...",
      "currency": "USD",
      "amount": 10,
      "email": "creator1@example.com",
      "payout_link": "https://payout.example/..."
    }
  ]
}
```

If any entry fails in immediate mode, the response `success` will be `false` and `results` will contain both successes and failures.

## POST /sdk/v1/payouts/pending

Fetch a single pending payout preview/status by `pending_payout_id`.

### Body

```json theme={null}
{ "pending_payout_id": "pnd_..." }
```

### Response

```json theme={null}
{
  "success": true,
  "data": {
    "pending_payout_id": "pnd_...",
    "createdAt": "2026-02-19T00:00:00.000Z",
    "expiresAt": "2026-02-26T00:00:00.000Z",
    "confirmedAt": null,
    "expired": false,
    "preview": { "payoutRecipientEmail": "creator@example.com", "payoutCurrency": "USD", "payoutAmount": 10 },
    "result": null
  }
}
```

## POST /sdk/v1/payouts/pending-bulk

Fetch multiple pending payout previews/statuses.

### Body

Accepts a string (comma-separated) or an array:

```json theme={null}
{ "pending_payout_ids": ["pnd_1", "pnd_2"] }
```

### Response

Returns found items plus `missing` IDs:

```json theme={null}
{
  "success": true,
  "data": [{ "pending_payout_id": "pnd_1", "preview": { "payoutAmount": 10 } }],
  "missing": ["pnd_2"]
}
```

## GET /sdk/v1/payouts/pending

List pending payouts for the application (table-friendly).

### Query parameters

* `page` (default `1`)
* `limit` (default `50`, max `100`)
* `includeExpired` (`true|false`, default `false`)
* `includeConfirmed` (`true|false`, default `false`)

### Response

Each row includes `expiresInSeconds` and `expired`.

```json theme={null}
{
  "success": true,
  "data": [
    {
      "pending_payout_id": "pnd_...",
      "createdAt": "2026-02-19T00:00:00.000Z",
      "expiresAt": "2026-02-26T00:00:00.000Z",
      "confirmedAt": null,
      "expired": false,
      "expiresInSeconds": 604800,
      "preview": { "payoutRecipientEmail": "creator@example.com", "payoutCurrency": "USD", "payoutAmount": 10 },
      "result": null
    }
  ],
  "pagination": { "page": 1, "limit": 50, "totalPages": 1, "totalItems": 1 }
}
```

## POST /sdk/v1/payouts/confirm

Confirm and execute a pending payout.

### Headers

* `X-Idempotency-Key` (required)

### Body

```json theme={null}
{ "pending_payout_id": "pnd_..." }
```

### Response

On success: `200` (example includes `payout_link` when the original trigger set `returnPayoutLink` to `true`)

```json theme={null}
{
  "success": true,
  "payoutId": "pay_...",
  "invoiceId": "inv_...",
  "currency": "USD",
  "amount": 10,
  "email": "creator@example.com",
  "payout_link": "https://payout.example/..."
}
```

If the pending payout is expired: `410 { "success": false, "message": "Pending payout has expired." }`

## POST /sdk/v1/payouts/confirm-bulk

Confirm and execute up to 100 pending payouts.

### Headers

* `X-Idempotency-Key` (required)

### Body

Accepts a string (comma-separated) or an array:

```json theme={null}
{ "pending_payout_ids": ["pnd_1", "pnd_2"] }
```

### Response

`success` is `true` only if **all** confirmations returned `status: 200`.

```json theme={null}
{
  "success": false,
  "results": [
    { "pending_payout_id": "pnd_1", "status": 200, "response": { "success": true, "payoutId": "pay_..." } },
    { "pending_payout_id": "pnd_2", "status": 410, "response": { "success": false, "message": "Pending payout has expired." } }
  ]
}
```

## POST /sdk/v1/payouts/status

Fetch payout status records for specific payout IDs (up to 100).

### Body

Accepts multiple aliases; preferred:

```json theme={null}
{ "payout_ids": ["pay_1", "pay_2"] }
```

### Response

Results preserve request order for found items and include `missing`.

```json theme={null}
{
  "success": true,
  "data": [{ "payoutId": "pay_1", "status": "sent", "currency": "USD" }],
  "missing": ["pay_2"]
}
```

## POST /sdk/v1/payouts/cancel

Cancel an in-flight payout.

### Headers

* `X-Idempotency-Key` (required)

### Body

Provide either `payoutId` or `payoutReferenceId`:

```json theme={null}
{ "payoutId": "pay_..." }
```

### Response

```json theme={null}
{
  "success": true,
  "data": { "refundedUsd": 10 }
}
```

If the payout was already cancelled, the response may include:

```json theme={null}
{
  "success": true,
  "data": { "refundedUsd": 10, "alreadyCancelled": true }
}
```

## GET /sdk/v1/payouts

List agency payouts.

### Query parameters

* `page` (default `1`)
* `limit` (default `50`, max `100`)
* `sortBy` (optional)
* `sortOrder` (`asc|desc`, default `desc`)
* `search` (optional)
* `payoutType` (optional; currently supports `DIRECT`)
* `statuses` (optional; comma-separated)
* `from` and `to` (optional; ISO timestamps)

If `from`/`to` is provided without a timezone offset, it is treated as UTC.

Supported `statuses` values (invalid values are ignored):

`processing`, `created`, `delivery_pending`, `delivery_failed`, `sent`, `delivered`, `claimed`, `reversed`, `canceled`, `expired`, `failed`, `pending`, `completed`, `flagged`, `delayed`

### Response

```json theme={null}
{
  "success": true,
  "data": [{ "payoutId": "pay_...", "status": "claimed", "currency": "USD" }],
  "pagination": { "page": 1, "limit": 50, "totalPages": 1, "totalItems": 1 },
  "meta": { "bufferBusinessDays": 1, "accelerated": false, "bankClosedDates": [] }
}
```

## GET /sdk/v1/payouts/export

Export payouts as CSV or PDF.

### Query parameters

* `format` (required): `csv` or `pdf`
* `from` and `to` (required): ISO timestamps
* All filters supported by `GET /sdk/v1/payouts` (`statuses`, `search`, `sortBy`, `sortOrder`, ...)
* `timeZone` (optional; used for PDF rendering)

### Responses

* `text/csv` with `Content-Disposition: attachment; filename="payout-transactions-YYYY-MM-DD.csv"`
* `application/pdf` with `Content-Disposition: attachment; filename="payout-transactions-YYYY-MM-DD.pdf"`

If the export would exceed 10,000 rows: `413` with a JSON error.
