# Pay creators

Pay what creators earned by card in one charge, from a prepaid balance, or on your own rails, with a 4% fee (minimum $0.50) added on top.

Approved earnings sit in a hold (10 days by default), then become **payable** and `campaign_payout.payable` fires. From there you pay in one of three ways, depending on the campaign's `settlement`.

| Way to pay | `settlement` | How |
| --- | --- | --- |
| Card, in one charge | `treasury` | `POST /v1/creator-campaigns/{campaignId}/payout-batches` charges your saved card and pays every selected creator |
| From your Pozy balance | `treasury` | Top up the balance, then settle creators one by one |
| Your own rails | `external` | Pay outside Pozy, then record it so balances stay right |

> **Enabled on request:**
> 
> Moving money through Pozy (payout batches, top-ups, transfers, balances, payees and the ledger) is turned on per workspace. If a call returns `403 feature_not_available`, contact support@pozy.ai.

## Fees

Every transfer to one creator carries one fee: 4% of the amount, with a $0.50 minimum. The fee is added on top, so the creator receives the full amount they earned.

| Creator is owed | Fee | You pay |
| --- | --- | --- |
| $5.00 | $0.50 (minimum) | $5.50 |
| $12.50 | $0.50 | $13.00 |
| $100.00 | $4.00 | $104.00 |
| $2,500.00 | $100.00 | $2,600.00 |

The minimum applies below $12.50. Card processing costs come out of the 4%, so there is no separate card fee. Paying one creator twice costs two fees. A transfer that is refused charges no fee, and the amount goes back to payable. Tracking, review, the ledger and the creator page are free.

## Who can move money

Only the workspace owner, admins and billing admins can pay, signed in or with a full-scope API key they created. Profile-scoped keys cannot read the balance, transfers or payees.

## Pay by card

One charge on your saved card covers every payable creator you select. No balance is needed and nothing waits on a hold.

```bash cURL
curl -X POST https://api.pozy.ai/v1/creator-campaigns/6701a2b3c4d5e6f7a8b9c0d1/payout-batches \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Idempotency-Key: payout-launch-clips-2026-11-15" \
  -H "Content-Type: application/json" \
  -d '{ "excludeParticipantIds": ["6702b3c4d5e6f7a8b9c0d1e2"] }'
```
```ts Node
const res = await fetch("https://api.pozy.ai/v1/creator-campaigns/6701a2b3c4d5e6f7a8b9c0d1/payout-batches", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.POZY_API_KEY}`,
    "Idempotency-Key": "payout-launch-clips-2026-11-15",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ excludeParticipantIds: ["6702b3c4d5e6f7a8b9c0d1e2"] }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.batch.id, data.batch.totalCents, data.payment.status);
```
```python Python
import os, requests

resp = requests.post(
    "https://api.pozy.ai/v1/creator-campaigns/6701a2b3c4d5e6f7a8b9c0d1/payout-batches",
    headers={
        "Authorization": f"Bearer {os.environ['POZY_API_KEY']}",
        "Idempotency-Key": "payout-launch-clips-2026-11-15",
    },
    json={"excludeParticipantIds": ["6702b3c4d5e6f7a8b9c0d1e2"]},
    timeout=60,
)
batch = resp.json()
print(batch["batch"]["status"], batch["payment"]["status"])
```

- Leave out `participantIds` to pay everyone payable. `excludeParticipantIds` leaves some out. `paymentMethodId` picks a card other than the default.
- The response has the `batch` (`amountCents`, `feeCents`, `totalCents`, one item per creator) and the `payment` status: `succeeded`, `processing` or `requires_action`.
- Creators who have not finished payout setup are skipped and stay payable.
- `campaign_payout.settled` fires once per creator paid. `campaign_payout.failed` fires if a payout does not reach the creator.

### When the bank asks for confirmation

`payment.status: "requires_action"` means the card issuer wants the payer to confirm (3-D Secure). Complete it in the browser with Stripe.js `handleNextAction({ clientSecret })` using `payment.clientSecret`, then call `POST /v1/payout-batches/{batchId}/confirm`. A batch left unconfirmed is cancelled after 30 minutes. `POST /v1/payout-batches/{batchId}/cancel` cancels it sooner and makes the creators payable again.

| Batch status | Meaning |
| --- | --- |
| `awaiting_payment` | Waiting for the charge or the bank confirmation |
| `paying` | Charged. Transfers are going out. |
| `paid` | Every item paid |
| `partially_failed`, `failed` | Some or all transfers failed. Failed items show a `failureReason` and go back to payable. |
| `expired` | Never confirmed |

> **Card limit:**
> 
> Each workspace starts with an instant card payout limit of $10,000 per rolling 30 days, counting the total charged with fees. Over the limit, the batch returns `402 payment_required`. Pay from your balance instead, or ask support to raise the limit.

## Pay from your balance

### Top up

`POST /v1/balance/top-ups` with `amountCents` and `method: "card"` charges your saved card. The balance is credited with what the card processor delivers after its processing fee, as soon as the charge succeeds.

```bash
curl -X POST https://api.pozy.ai/v1/balance/top-ups \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Idempotency-Key: topup-2026-11-01" \
  -H "Content-Type: application/json" \
  -d '{ "amountCents": 200000, "method": "card" }'
```

- Money from a card top-up can be paid to creators from 7 days after the charge. `GET /v1/balance` shows `availableCents` and the `payoutLocks` with each `unlocksAt`.
- A top-up that needs bank confirmation returns `requires_action` with a `clientSecret`. Finish it, or it is cancelled after 30 minutes. `POST /v1/balance/top-ups/{topupId}/cancel` cancels it sooner.
- `GET /v1/balance/top-ups/{topupId}/receipt` returns the receipt.
- Bank transfer top-ups are not available yet.

### Settle a creator

`POST /v1/creator-campaigns/{campaignId}/participants/{participantId}/settle` pays one creator from the balance. Leave out `amountCents` to pay everything payable. The fee is debited with the payout.

```bash
curl -X POST https://api.pozy.ai/v1/creator-campaigns/6701a2b3c4d5e6f7a8b9c0d1/participants/6702b3c4d5e6f7a8b9c0d1e3/settle \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Idempotency-Key: settle-cleo-2026-11" \
  -H "Content-Type: application/json" \
  -d '{}'
```

> **Always send an Idempotency-Key:**
> 
> A settle moves real money. The `Idempotency-Key` is what stops a network retry from paying the same creator twice.

## Pay on your own rails

For `settlement: "external"`, pay the creator however you like, then record the payment so their balance and your report stay correct: call the same settle endpoint with `recordOnly: true` and your own `externalReference` (a bank reference or invoice number, up to 200 characters). No money moves through Pozy and no fee is charged.

## Creator payout setup

Before a creator can receive money through Pozy, they finish payout onboarding from their campaign page (or `POST /public/creator-campaigns/{token}/payouts` with `action: "onboard"`). Their participant record shows `payout.status`: `not_started`, `onboarding`, `ready` or `restricted`. Creators download a statement for each payout from their page.

For your own flows, `GET /v1/payees` lists everyone you can pay with their `onboardingStatus` and `payoutsEnabled`, and `POST /v1/payees/{payeeId}/onboarding-link` creates a fresh onboarding link to send them.

## Transfers and the ledger

- `POST /v1/transfers` sends a balance transfer to a payee (`payeeId`, `amountCents`, optional `reference`). `GET /v1/transfers` and `GET /v1/transfers/{transferId}` read them back with `status` (`pending`, `paid`, `failed`, `reversed`).
- `GET /v1/ledger/balances` and `GET /v1/ledger/entries` give the money view across campaigns.
- `GET /v1/creator-campaigns/{campaignId}/payables` lists who is payable on one campaign and how much.

A card dispute on a payout charge is debited from your balance, which can go negative. Payouts stop until it is covered.

## Errors

| Status | Code | Cause | Fix |
| --- | --- | --- | --- |
| `403` | `feature_not_available` | Money movement is not enabled for the workspace | Contact support@pozy.ai |
| `403` | | Your role cannot move money, or the key is not full scope | Use an owner, admin or billing admin and a full-scope key |
| `402` | `payment_required` | Over the instant card payout limit | Pay from balance, or ask support to raise it |
| `402` | | Balance below the amount plus fee on a settle | Top up, or pay by card |
| `409` | | The creator has not finished payout setup, or a payout is already in progress | Ask the creator to finish setup, or retry later |

## Endpoints

| Endpoint | What it does |
| --- | --- |
| [`GET /v1/creator-campaigns/{campaignId}/payables`](https://pozy.ai/docs/api/listCampaignPayables) | List campaign payables |
| [`POST /v1/creator-campaigns/{campaignId}/payout-batches`](https://pozy.ai/docs/api/createCampaignPayoutBatch) | Pay creators with one card payment |
| [`GET /v1/creator-campaigns/{campaignId}/payout-batches`](https://pozy.ai/docs/api/listCampaignPayoutBatches) | List payout batches |
| [`GET /v1/payout-batches/{batchId}`](https://pozy.ai/docs/api/getPayoutBatch) | Get a payout batch |
| [`POST /v1/payout-batches/{batchId}/confirm`](https://pozy.ai/docs/api/confirmPayoutBatch) | Confirm a payout batch payment |
| [`POST /v1/payout-batches/{batchId}/cancel`](https://pozy.ai/docs/api/cancelPayoutBatch) | Cancel an unpaid payout batch |
| [`POST /v1/creator-campaigns/{campaignId}/participants/{participantId}/settle`](https://pozy.ai/docs/api/settleCampaignParticipant) | Settle campaign participant |
| [`GET /v1/creator-campaigns/{campaignId}/ledger`](https://pozy.ai/docs/api/listCampaignLedger) | List campaign ledger |

| Endpoint | What it does |
| --- | --- |
| [`GET /v1/ledger/balances`](https://pozy.ai/docs/api/getLedgerBalances) | Get ledger balances |
| [`GET /v1/ledger/entries`](https://pozy.ai/docs/api/listLedgerEntries) | List ledger entries |
| [`GET /v1/balance`](https://pozy.ai/docs/api/getBalance) | Get balance |
| [`GET /v1/balance/top-ups`](https://pozy.ai/docs/api/listTopups) | List top-ups |
| [`POST /v1/balance/top-ups`](https://pozy.ai/docs/api/createTopup) | Create a top-up |
| [`GET /v1/balance/top-ups/{topupId}/receipt`](https://pozy.ai/docs/api/getTopupReceipt) | Get a top-up receipt |
| [`POST /v1/balance/top-ups/{topupId}/confirm`](https://pozy.ai/docs/api/confirmTopup) | Confirm a top-up |
| [`POST /v1/balance/top-ups/{topupId}/cancel`](https://pozy.ai/docs/api/cancelTopup) | Cancel a top-up |
| [`GET /v1/payees`](https://pozy.ai/docs/api/listPayees) | List payees |
| [`POST /v1/payees/{payeeId}/onboarding-link`](https://pozy.ai/docs/api/createPayeeOnboardingLink) | Create a payee onboarding link |
| [`GET /v1/transfers`](https://pozy.ai/docs/api/listTransfers) | List transfers |
| [`POST /v1/transfers`](https://pozy.ai/docs/api/createTransfer) | Create a transfer |
| [`GET /v1/transfers/{transferId}`](https://pozy.ai/docs/api/getTransfer) | Get a transfer |
| [`GET /v1/payout-batches/{batchId}`](https://pozy.ai/docs/api/getPayoutBatch) | Get a payout batch |
| [`POST /v1/payout-batches/{batchId}/confirm`](https://pozy.ai/docs/api/confirmPayoutBatch) | Confirm a payout batch payment |
| [`POST /v1/payout-batches/{batchId}/cancel`](https://pozy.ai/docs/api/cancelPayoutBatch) | Cancel an unpaid payout batch |

## Webhook events

| Event | When it fires |
| --- | --- |
| [`campaign_payout.payable`](https://pozy.ai/docs/webhooks/events#campaign-payout-payable) | Campaign payout payable. |
| [`campaign_payout.settled`](https://pozy.ai/docs/webhooks/events#campaign-payout-settled) | Campaign payout settled. |
| [`campaign_payout.failed`](https://pozy.ai/docs/webhooks/events#campaign-payout-failed) | Campaign payout failed. |
