post_finance_clawbacks_by_id_execute

Changes data · you confirm first

Calls POST /api/finance/clawbacks/{id}/execute as the signed-in person · REST reference

Send an approved clawback's notice if it has not been, then execute it (platform staff)

The retry for an approval whose notice or execution did not finish. Sends the written notice when noticeSentAt is null (nothing is recovered before it — 409 CLAWBACK_NOTICE_NOT_SENT when it still cannot be sent), then reverses the payout's Stripe transfer by what is still owed, records what the clinic's Stripe balance covered, and offsets credit the clinic holds. A reversal already booked is not repeated; a reversal Stripe refuses is recorded FAILED and answered 200 with error, so it can be executed again. PFF_DISCRETIONARY recovers by offset only. When the payout names no transfer (needsTransferId), give it as originalStripeTransferId.

Arguments

ArgumentTypeDescription
idpathstring (uuid)required
bodyJSONobjectThe request body, as a JSON object. Its fields are listed below.

Fields of body

FieldTypeDescription
originalStripeTransferIdstring | nullThe payout's Stripe transfer, only when the clawback's payout names none.

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_clawbacks_by_id_execute",
    "arguments": {
      "id": "11111111-1111-4111-8111-111111111111",
      "body": {
        "originalStripeTransferId": "string"
      }
    }
  }
}
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 clawback's detail after the attempt, and what the execution did

json
{
  "clawback": {
    "clawback": {
      "amount": 1,
      "approvedAt": 1,
      "approvedBy": "11111111-1111-4111-8111-111111111111",
      "creditedAmount": 1,
      "currency": "string",
      "deniedAt": 1,
      "deniedBy": "11111111-1111-4111-8111-111111111111",
      "feeCents": 1,
      "feeLiability": {},
      "feeWaiverConsumed": true,
      "filedBy": "SERVICE_PROVIDER",
      "id": "11111111-1111-4111-8111-111111111111",
      "initiatedBy": "11111111-1111-4111-8111-111111111111",
      "initiatorOrgId": "11111111-1111-4111-8111-111111111111"
    },
    "connectBalance": 1,
    "connectBalanceAt": 1,
    "legs": [
      {}
    ],
    "needsTransferId": true,
    "owedCents": 1
  },
  "execution": {
    "clawbackId": "11111111-1111-4111-8111-111111111111",
    "connectBalance": 1,
    "error": "string",
    "offsets": [
      {}
    ],
    "reversalRecovered": 1,
    "stripeReversalId": "string",
    "transferReversalState": "NOT_ATTEMPTED"
  }
}

Fields

FieldTypeDescription
clawbackobjectOne clawback with everything its detail drawer shows.
clawback.clawbackobjectA clawback as the platform review queue reads it — with how often Pawsitive Future has absorbed the clinic's fees before, and how its notice, reversal and recovery stand.
clawback.clawback.amountintegerCENTS asked back — at most creditedAmount.
clawback.clawback.approvedAtinteger | null
clawback.clawback.approvedBystring (uuid) | null
clawback.clawback.creditedAmountintegerCENTS the voucher's approval credited — what its payout paid.
clawback.clawback.currencystring
clawback.clawback.deniedAtinteger | null
clawback.clawback.deniedBystring (uuid) | null
clawback.clawback.feeCentsintegerCENTS of recovery fee assessed; 0 until a fee is realized.
clawback.clawback.feeLiabilityobject | nullProposed when Pawsitive Future files the clawback, set by an approval; null on a clinic's filing until it is approved, and on a denial.
clawback.clawback.feeWaiverConsumedbooleanWhether Pawsitive Future absorbs this approved clawback's processing cost.
clawback.clawback.filedBy"SERVICE_PROVIDER" | "PAWSITIVE_FUTURE"Who filed a clawback — the service provider that was paid, or Pawsitive Future staff.
clawback.clawback.idstring (uuid)The clawback's ledger transaction.
clawback.clawback.initiatedBystring (uuid) | nullThe user who filed it.
clawback.clawback.initiatorOrgIdstring (uuid) | nullThe service provider that filed it; null when Pawsitive Future did.
clawback.clawback.memostring | null
clawback.clawback.orgIdstring (uuid)The service provider the payout went to.
clawback.clawback.orgNamestring | null
clawback.clawback.paidAtinteger | nullEpoch milliseconds the voucher was paid out.
clawback.clawback.payoutStripeTransferIdstring | nullThat payout's Stripe transfer (tr_…), when it recorded one.
clawback.clawback.payoutTransactionIdstring (uuid) | nullThe org's PAYOUT settlement created at the voucher's paidAt; null when none matches.
clawback.clawback.reasonCode"PFF_DISCRETIONARY" | "PROCEDURE_NOT_COMPLETED" | "BENEFICIARY_DISPUTE" | "DUPLICATE_OR_ERRONEOUS_PAYOUT" | "DONATION_REVERSED" | "OTHER"Why a clawback was filed. A service provider files PROCEDURE_NOT_COMPLETED, BENEFICIARY_DISPUTE or OTHER about a payout it received; the rest are Pawsitive Future's findings. OTHER needs a memo of at least 20 characters.
clawback.clawback.requestedAtintegerEpoch milliseconds.
clawback.clawback.status"REQUESTED" | "APPROVED" | "DENIED" | "EXECUTING" | "RECOVERED" | "PARTIALLY_RECOVERED" | … (7 values)A payout clawback's lifecycle, kept apart from its ledger transaction's status. Filing and deciding reach REQUESTED, APPROVED and DENIED; the rest follow execution. RECOVERED is "cash confirmed": Pawsitive Future has confirmed the full amount is back in hand, never merely a booked reversal.
clawback.clawback.transferReversalStateobject | null
clawback.clawback.voucherCodestring
clawback.clawback.voucherIdstring (uuid)
clawback.clawback.voucherValueReversedboolean | nullDecided at approval, beside the money: whether the voucher stops counting as help delivered once the clawback resolves. Null until approved, and on a denial.
clawback.clawback.voucherValueReversedByDefaultboolean | nullWhat an approval records as voucherValueReversed when the approver does not say — set by the reason: true for PROCEDURE_NOT_COMPLETED, BENEFICIARY_DISPUTE and DUPLICATE_OR_ERRONEOUS_PAYOUT, false for DONATION_REVERSED. Null for PFF_DISCRETIONARY and OTHER, which have no default: an approval must say.
clawback.clawback.cashConfirmationSourcestring | nullThe kinds of recovery the confirmed cash came by, comma-joined.
clawback.clawback.cashConfirmedAtinteger | nullWhen the full amount was confirmed back — what RECOVERED means.
clawback.clawback.noticeMessageIdstring | null
clawback.clawback.noticeSentAtinteger | nullWhen the service provider was sent the written notice. Null after an approval means the notice did not send: nothing is recovered, payouts are paused, and POST /api/finance/clawbacks/{id}/execute retries it.
clawback.clawback.offsetPendingAmountintegerCENTS its offset payouts have moved that no OFFSET leg has recorded yet — settled, the transfer not confirmed. A failed one stays counted until the reconcile records it or it is released (POST /api/finance/clawbacks/{id}/offsets/{payoutTransactionId}/release).
clawback.clawback.originalStripeTransferIdstring | nullThe payout transfer (tr_…) the reversal reverses.
clawback.clawback.outstandingAmountintegerCENTS still owed while it is being collected (APPROVED, EXECUTING); 0 once closed.
clawback.clawback.pausesPayoutsbooleanWhether this clawback pauses its service provider's payouts: APPROVED or EXECUTING, or PARTIALLY_RECOVERED / WRITTEN_OFF until payouts are resumed.
clawback.clawback.payoutsResumedAtinteger | null
clawback.clawback.payoutsResumedBystring (uuid) | null
clawback.clawback.payoutsResumedReasonstring | null
clawback.clawback.recoveredAmountintegerCENTS recovered so far — its confirmed recovery legs.
clawback.clawback.stripeReversalIdstring | nullThe transfer reversal (trr_…), once booked.
clawback.clawback.transferReversalLastErrorstring | nullThe last failed reversal attempt's error; null once one succeeds.
clawback.clawback.transferReversalUpdatedAtinteger | nullEpoch milliseconds the reversal outbox state was last written; null when none was. A PENDING older than two minutes is read as a reversal whose synchronous call died.
clawback.clawback.writtenOffAtinteger | null
clawback.clawback.writtenOffBystring (uuid) | null
clawback.clawback.writtenOffMemostring | null
clawback.clawback.feesAbsorbedBeforeintegerHow many of the service provider's other approved clawbacks Pawsitive Future absorbed the processing cost of — what the approver weighs for a repeat.
clawback.connectBalanceinteger | nullThe clinic's Stripe balance as Stripe last reported it, CENTS, signed — negative while a reversal is uncovered. Null when none was recorded.
clawback.connectBalanceAtinteger | null
clawback.legsarray of objectIts recovery legs, oldest first.
clawback.legs[].amountintegerCENTS.
clawback.legs[].clawbackIdstring (uuid)
clawback.legs[].confirmedbooleanWhether it is cash.
clawback.legs[].confirmedAtinteger | null
clawback.legs[].createdAtinteger
clawback.legs[].currencystring
clawback.legs[].idstring (uuid)
clawback.legs[].kind"REVERSAL" | "OFFSET" | "BANK_DEBIT" | "OUT_OF_BAND" | "CLINIC_PAYMENT"

More fields follow; the REST reference lists them all.

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

No such clawback.

409

The clawback is not APPROVED or EXECUTING (CLAWBACK_NOT_EXECUTABLE), no Stripe transfer is known for its payout (CLAWBACK_TRANSFER_UNKNOWN), or the written notice could not be sent (CLAWBACK_NOTICE_NOT_SENT) — nothing was recovered, the clawback stays APPROVED, and the same call retries.

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_clawbacks_by_id_execute",
  "description": "POST /api/finance/clawbacks/{id}/execute — The retry for an approval whose notice or execution did not finish. Sends the written notice when `noticeSentAt` is null (nothing is recovered before it — 409 `CLAWBACK_NOTICE_NOT_SENT` when it still cannot be sent), then reverses the payout's Stripe transfer by what is still owed, records what the clinic's Stripe balance covered, and offsets credit the clinic holds. A reversal already booked is not repeated; a reversal Stripe refuses is recorded FAILED and answered 200 with `error`, so it can be executed again. PFF_DISCRETIONARY recovers by offset only. When the payout names no transfer (`needsTransferId`), give it as `originalStripeTransferId`.\n\nThis changes data. The person is asked to confirm it before it runs, and nothing happens if they decline.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "id": {
        "type": "string"
      },
      "body": {
        "type": "string",
        "description": "The JSON request body: { originalStripeTransferId: string (The payout's Stripe transfer, only when the clawback's payout names none.) }"
      }
    },
    "required": [
      "id"
    ]
  },
  "annotations": {
    "readOnlyHint": false,
    "destructiveHint": true,
    "idempotentHint": false,
    "openWorldHint": false
  }
}