post_finance_payouts_run

Changes data · you confirm first

Calls POST /api/finance/payouts/run as the signed-in person · REST reference

Settle one organization's accrued balance and pay it out

Drains the org's ORG_BALANCE into a Checkout plus a PAYOUT Transaction and moves its APPROVED vouchers to PAID, atomically in the DAL, then attempts the real Stripe Connect transfer. A SKIPPED RUN IS A 200, NOT AN ERROR: when the org's EFT is not payout-ready, or there is no balance, the funds are retained and the body carries paid: false with skippedReason. A client that branches on the status code alone cannot tell a settlement from a skip. The stripe* fields appear only on a run that actually attempted a transfer. stripeTransferError present alongside paid: true is the money-at-risk case: the ledger settled and the transfer did not. A failure is answered as /eft/onboard answers one: the DAL's refusal by its code, 503 when the DAL cannot be reached, 500 otherwise, and no upstream text.

Arguments

ArgumentTypeDescription
bodyJSONobjectrequiredThe request body, as a JSON object. Its fields are listed below.

Fields of body

FieldTypeDescription
orgIdstring (uuid)required

Example call

A client sends this over the MCP session; Claude and other agents build it for you. The values are placeholders — the shape is real.

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "post_finance_payouts_run",
    "arguments": {
      "body": {
        "orgId": "11111111-1111-4111-8111-111111111111"
      }
    }
  }
}
Confirmation
The client shows the person the exact request and waits. Nothing runs until they tick Make this change. See Reading and changing.

Result

On success (HTTP 200) the tool returns one text item holding the API's JSON, pretty-printed.

The run's outcome — settled OR skipped. Check paid.

json
{
  "amount": 1,
  "currency": "string",
  "event": {
    "aggregateId": "string",
    "eventType": "string"
  },
  "newBalance": 1,
  "orgId": "11111111-1111-4111-8111-111111111111",
  "paid": true,
  "checkoutId": "11111111-1111-4111-8111-111111111111",
  "skippedReason": "string",
  "stripeDestination": "string",
  "stripeTransferError": "string",
  "stripeTransferId": "string",
  "transactionId": "11111111-1111-4111-8111-111111111111",
  "vouchersPaid": 1
}

Fields

FieldTypeDescription
amountintegerAmount settled in CENTS. 0 when skipped.
checkoutIdstring (uuid) | null
currencystring
eventobjectA NARROWED domain event — two fields only, not the full PayoutEvent the SDL declares.
event.aggregateIdstring
event.eventTypestring
newBalanceintegerThe org's balance after the run, in CENTS.
orgIdstring (uuid)
paidbooleanTrue when a settlement occurred; false when skipped and funds retained.
skippedReasonstring | nullWhy nothing was paid. Null on a settled run.
stripeDestinationstringThe Connect account the money went to.
stripeTransferErrorstringPresent when the transfer FAILED after the ledger had already settled — the ledger says PAID and the clinic has no money.
stripeTransferIdstringPresent only when a real transfer was created.
transactionIdstring (uuid) | nullThe PAYOUT Transaction recording the debit.
vouchersPaidintegerNumber of vouchers moved APPROVED to PAID.

When it fails

A failed call returns isError: true with the API's message as text. A change the person declines, or lets time out, also comes back this way and nothing changes.

400

The request was malformed or failed a guard.

403

Authenticated, but the caller holds none of the required permissions.

404

The DAL found no such organization. Carries the DAL's sentence.

What the model is shown

This is the tool exactly as the server lists it in tools/list. The description starts with the REST call it makes.

json
{
  "name": "post_finance_payouts_run",
  "description": "POST /api/finance/payouts/run — Drains the org's ORG_BALANCE into a Checkout plus a PAYOUT Transaction and moves its APPROVED vouchers to PAID, atomically in the DAL, then attempts the real Stripe Connect transfer. A SKIPPED RUN IS A 200, NOT AN ERROR: when the org's EFT is not payout-ready, or there is no balance, the funds are retained and the body carries `paid: false` with `skippedReason`. A client that branches on the status code alone cannot tell a settlement from a skip. The `stripe*` fields appear only on a run that actually attempted a transfer. `stripeTransferError` present alongside `paid: true` is the money-at-risk case: the ledger settled and the transfer did not. A failure is answered as `/eft/onboard` answers one: the DAL's refusal by its code, 503 when the DAL cannot be reached, 500 otherwise, and no upstream text.\n\nThis changes data. The person is asked to confirm it before it runs, and nothing happens if they decline.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "body": {
        "type": "string",
        "description": "The JSON request body: { orgId*: string }"
      }
    },
    "required": [
      "body"
    ]
  },
  "annotations": {
    "readOnlyHint": false,
    "destructiveHint": true,
    "idempotentHint": false,
    "openWorldHint": false
  }
}