# Finance · Payouts

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## GET /finance/payouts

**List payouts**

`operationId: PayoutController_listPayouts`

Lists payouts with optional filters and paging. Filter on `status=pending` for the approval queue.

#### Signature

```http
GET /finance/payouts (recipientType?: string, recipientId?: string, walletId?: string, status?: string, page?: integer, pageSize?: integer) -> A page of payouts
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /finance/payouts/{payoutId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `recipientType` | query | string | — |  |
| `recipientId` | query | string | — |  |
| `walletId` | query | string | — |  |
| `status` | query | "pending" \| "approved" \| "processing" \| "completed" \| "failed" \| "cancelled" | — |  |
| `page` | query | integer | — | Page number. Values below 1 are clamped to 1. |
| `pageSize` | query | integer | — | Page size. Clamped to 1–500; a larger value is silently reduced. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | A page of payouts |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /finance/wallets/{walletId}/payout-summary

**Get a wallet's payout summary**

`operationId: PayoutController_getWalletPayoutSummary`

Totals and counts by status for one wallet — how much has been paid out, how much is pending, how much failed. The figures behind a host's earnings page.

#### Signature

```http
GET /finance/wallets/{walletId}/payout-summary (walletId: string) -> Payout totals and counts by status
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | — | Wallet not found | No wallet in the org has that id. | List wallets with `GET /finance/wallets`, or look one up by owner. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /finance/stats/payouts`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `walletId` | path | string | yes | Wallet id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Payout totals and counts by status |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Wallet not found — No wallet in the org has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /finance/payouts/{payoutId}

**Get a payout**

`operationId: PayoutController_getPayout`

Fetches one payout by id, with its status and any external reference.

#### Signature

```http
GET /finance/payouts/{payoutId} (payoutId: string) -> The payout
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | — | Payout not found | No payout in the org has that id. | List payouts with `GET /finance/payouts`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /finance/payouts/number/lookup`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `payoutId` | path | string | yes | Payout id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The payout |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Payout not found — No payout in the org has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /finance/payouts/number/lookup

**Get a payout by number**

`operationId: PayoutController_getPayoutByNumber`

Finds a payout by its human-readable number rather than its id — the number that appears on a remittance advice or a support ticket.

#### Signature

```http
GET /finance/payouts/number/lookup (payoutNumber?: string) -> The payout
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /finance/payouts/{payoutId}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `payoutNumber` | query | string | yes | The payout number. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The payout |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /finance/wallets/{walletId}/request-payout

**Request a payout from a wallet**

`operationId: PayoutController_requestPayout`

Creates a payout request against a wallet's available balance. The payout starts `pending` and must be approved, processed and completed before money actually moves.

Every rule on the wallet is checked here, and each has its own error: the wallet must be active, the amount must be within `availableBalance`, above `minPayout`, below `maxPayout`, inside the daily limit, and a payout method must exist and be enabled.

#### Signature

```http
POST /finance/wallets/{walletId}/request-payout (walletId: string, body) -> The created payout, pending approval
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Notes

- Requesting does not move money. The payout must go through approve → process → complete.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | — | Wallet not found | No wallet in the org has that id. | List wallets with `GET /finance/wallets`, or look one up by owner. |
| `400` | — | Wallet is not active | The wallet is frozen or otherwise not active. | Unfreeze it with `POST /finance/wallets/{walletId}/unfreeze`. A frozen wallet accepts no movement in either direction. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /finance/payouts/{payoutId}/approve`
- `PUT /finance/wallets/{walletId}/payout-settings`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `walletId` | path | string | yes | Wallet id. |

### Request body

How much to pay out, and how.

```json
{
  "amount": 500,
  "method": "bank_transfer",
  "notes": "Monthly settlement"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The created payout, pending approval |
| `400` | Wallet is not active — The wallet is frozen or otherwise not active. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Wallet not found — No wallet in the org has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /finance/payouts/{payoutId}/approve

**Approve a payout**

`operationId: PayoutController_approvePayout`

Authorises a pending payout for processing. Only a `pending` payout can be approved — this is the control point before money leaves.

`approvedBy` is recorded, so the audit trail names who authorised it.

#### Signature

```http
POST /finance/payouts/{payoutId}/approve (payoutId: string, body) -> The approved payout
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | — | Payout not found | No payout in the org has that id. | List payouts with `GET /finance/payouts`. |
| `400` | NOT_PENDING | Payout is not pending | The payout has already been approved, processed, or closed. | Read the payout first — approval is not idempotent. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /finance/payouts/{payoutId}/process`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `payoutId` | path | string | yes | Payout id. |

### Request body

Who approved it.

```json
{
  "approvedBy": "finance@appmint.io",
  "notes": "Verified against August bookings"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The approved payout |
| `400` | Payout is not pending — The payout has already been approved, processed, or closed. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Payout not found — No payout in the org has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /finance/payouts/{payoutId}/process

**Process a payout**

`operationId: PayoutController_processPayout`

Moves an approved payout into `processing` — it has been handed to whatever actually transfers the money. Mark the outcome with `complete` or `fail`.

#### Signature

```http
POST /finance/payouts/{payoutId}/process (payoutId: string) -> The processing payout
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | — | Payout not found | No payout in the org has that id. | List payouts with `GET /finance/payouts`. |
| `400` | — | Payout cannot be processed | The payout is not in a state that allows processing — typically it has not been approved. | Approve it first. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /finance/payouts/{payoutId}/complete`
- `POST /finance/payouts/{payoutId}/fail`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `payoutId` | path | string | yes | Payout id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The processing payout |
| `400` | Payout cannot be processed — The payout is not in a state that allows processing — typically it has not been approved. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Payout not found — No payout in the org has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /finance/payouts/{payoutId}/complete

**Complete a payout**

`operationId: PayoutController_completePayout`

Marks a payout as successfully paid and debits the wallet. Record the `externalReference` from whatever moved the money — a bank transfer reference, a provider payout id — so the platform record can be reconciled against the bank.

#### Signature

```http
POST /finance/payouts/{payoutId}/complete (payoutId: string, body) -> The completed payout
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Notes

- Always record `externalReference` — without it, a platform payout cannot be matched to a bank line.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | — | Payout not found | No payout in the org has that id. | List payouts with `GET /finance/payouts`. |
| `400` | — | Payout status "<status>" cannot be completed | The payout is not in a state that can be completed. | A payout must be approved and processing before it can complete. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /finance/payouts/{payoutId}/fail`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `payoutId` | path | string | yes | Payout id. |

### Request body

The external reference for the transfer.

```json
{
  "externalReference": "BACS-99182"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The completed payout |
| `400` | Payout status "<status>" cannot be completed — The payout is not in a state that can be completed. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Payout not found — No payout in the org has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /finance/payouts/{payoutId}/fail

**Fail a payout**

`operationId: PayoutController_failPayout`

Records that a payout did not go through, with the reason. The wallet balance is not debited, so the funds remain available to try again.

#### Signature

```http
POST /finance/payouts/{payoutId}/fail (payoutId: string, body) -> The failed payout
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Notes

- Fix the payout method before requesting again, or the next attempt fails the same way.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | — | Payout not found | No payout in the org has that id. | List payouts with `GET /finance/payouts`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /finance/payouts/{payoutId}/complete`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `payoutId` | path | string | yes | Payout id. |

### Request body

Why it failed.

```json
{
  "reason": "Bank rejected — account closed",
  "code": "account_closed"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The failed payout |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Payout not found — No payout in the org has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /finance/payouts/{payoutId}/cancel

**Cancel a payout**

`operationId: PayoutController_cancelPayout`

Cancels a payout before it is paid, releasing the amount back to the wallet. Use this to withdraw a request; use `fail` when an attempt was made and rejected.

#### Signature

```http
POST /finance/payouts/{payoutId}/cancel (payoutId: string, body) -> The cancelled payout
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | — | Payout not found | No payout in the org has that id. | List payouts with `GET /finance/payouts`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /finance/payouts/{payoutId}/fail`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `payoutId` | path | string | yes | Payout id. |

### Request body

Why it is being cancelled.

```json
{
  "reason": "Requested in error"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The cancelled payout |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Payout not found — No payout in the org has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /finance/batch/payouts

**Process payouts for several wallets**

`operationId: PayoutController_processBatchPayouts`

Creates payouts across many wallets in one call — the monthly settlement run.

Use `minAmount` to skip wallets whose balance is not worth a transfer. Wallets that fail their own rules (below minimum, no payout method, frozen) are skipped rather than failing the batch, so **inspect the response** to see which ones actually produced a payout.

#### Signature

```http
POST /finance/batch/payouts (body) -> Per-wallet results, including those skipped
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Notes

- A `200` means the batch ran, not that every wallet was paid. Check each result.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /finance/wallets/{walletId}/request-payout`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

Which wallets to pay out, and a floor.

```json
{
  "walletIds": [
    "WAL-4821",
    "WAL-4822"
  ],
  "minAmount": 25
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Per-wallet results, including those skipped |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /finance/stats/payouts

**Get payout statistics**

`operationId: PayoutController_getPayoutStats`

Aggregate payout figures for the org — volume and value by status, including how much is pending approval.

#### Signature

```http
GET /finance/stats/payouts () -> Aggregate payout statistics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /finance/stats/wallets`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Aggregate payout statistics |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /finance/payouts/run-schedule

**Run the payout schedule**

`operationId: PayoutController_runScheduledPayouts`

Pays out each eligible wallet’s whole available balance, as the schedule would. With the org’s schedule set to `manual` nothing runs (`ran: false`) unless `force` is true. Wallets set to manual, without a destination, with nothing available, below their own minimum, or already mid-payout are skipped and reported with the reason.

#### Signature

```http
POST /finance/payouts/run-schedule (body) -> What ran
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

```json
{
  "force": true
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | What ran |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /finance/payouts/sweep

**Refresh every in-flight payout**

`operationId: PayoutController_sweepPayouts`

Backstop for a missed webhook: asks each rail where the org’s processing payouts stand, completing or failing them accordingly. Bank payouts are skipped — they settle with their ACH batch. One unreachable rail does not stop the sweep. Safe to call on a schedule.

#### Signature

```http
POST /finance/payouts/sweep () -> Counts
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /finance/payouts/{payoutId}/refresh-status`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Counts |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

Example response:

```json
{
  "checked": 4,
  "skipped": 2,
  "settled": 3,
  "failed": 0
}
```

## POST /finance/payouts/{payoutId}/refresh-status

**Refresh one payout from its rail**

`operationId: PayoutController_refreshPayoutStatus`

Asks the payout’s rail where it stands. Only a `processing` payout is checked; completed on the rail completes it here, failed fails it, anything else leaves it as is. A payout not processing, or on a rail with no status check, comes back unchanged.

#### Signature

```http
POST /finance/payouts/{payoutId}/refresh-status (payoutId: string) -> The payout
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`). Required role(s): `Staff — a signed-in business user; customer and site-app tokens are refused`.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | — | Payout not found | No payout in the org has that id. | List payouts with `GET /finance/payouts`. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `payoutId` | path | string | yes | Payout id. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The payout |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Payout not found — No payout in the org has that id. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

