---
title: "Settle a creator payment"
method: POST
path: "/campaigns/payments/settle"
tags: ["Campaigns"]
---

# Settle a creator payment

`POST /campaigns/payments/settle`

Triggers a real Stripe transfer + wallet debit when `reward_type='cash'`. `reward_type='custom'` records the settlement only — no money moves. Idempotency-Key is REQUIRED and the inner `PaymentService.settle` runs claim/release semantics so a retry with the same key can never double-pay. Every successful settlement emits an `audit.campaigns.settle` log line for on-call reconciliation. `X-Dry-Run: true` skips the Stripe call entirely.

## Headers

- `Idempotency-Key` string, nullable
- `X-Dry-Run` string, nullable

## Request body

- SettlePaymentRequest — ``POST /public/v1/campaigns/payments/settle`` — pay a creator out. Triggers a **real Stripe transfer + wallet debit** when ``reward_type='cash'``; ``reward_type='custom'`` records the settlement only (no money moves). Idempotency-Key is REQUIRED and the inner ``PaymentService.settle`` runs claim/release semantics so a retry with the same key can never double-pay.
  - `creator_id` integer, required
  - `campaign_id` integer, required
  - `amount` number, required — Settlement amount in the campaign's currency. Capped at $100,000 per call as a sanity guard.
  - `currency` string, required — ISO 4217 currency code (e.g. 'USD'). **Informational** — the shop's persisted wallet currency takes precedence at settlement time. If the wallet currency differs from this value, the transfer executes in the wallet currency without rejection. The response's ``currency`` field confirms the currency actually used for the transfer.
  - `reward_type` string, required — 'cash' triggers a Stripe transfer + wallet debit; 'custom' records the settlement only (no money moves).
  - `campaign_creator_mapping_id` integer, required — REQUIRED. The campaign-creator mapping id that the settlement is being recorded against. The portal surfaces this id on every creator row in ``GET /campaigns/{id}/detail`` and in the response to the accept endpoint, so callers always have it. Required because the underlying ``PaymentService.settle`` only runs its double-payment guard (``claim_for_settlement_sync``) when a mapping id is present — omitting it would leave the money-moving path with idempotency-only protection (a different ``Idempotency-Key`` per call could debit the wallet repeatedly with no DB-level guard).
  - `metadata` object, nullable — Free-form metadata stored alongside the settlement (e.g. agent annotation, internal reference).

## Response `201`

Successful Response

- SettlementResponse — 201 response for ``POST /campaigns/payments/settle``.
  - `success` boolean, required
  - `transfer_id` string, nullable — Stripe transfer id for cash settlements. Null for custom-reward settlements (no Stripe call).
  - `amount` number, nullable
  - `currency` string, nullable
  - `paid_at` string, nullable
  - `wallet_balance` number, nullable — Remaining wallet balance after the settlement.

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/reacherapp/apis/reacher-data-api.md) · [All operations](https://skmtc.dev/reacherapp/apis/reacher-data-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/reacherapp/reacher-data-api/revisions/d4fe3e380424/schema)
