post_vouchers_by_id_invalidate
Calls POST /api/vouchers/{id}/invalidate as the signed-in person · REST reference
Invalidate a voucher
Undoes a clinic's claim on a voucher and returns its value to the pool it came from. The DAL decides how from the voucher's current state, in one write. From VERIFIED, PERFORMED_PENDING_CLAIM or CLAIMED no money has moved: it mints a same-value CREATED replacement into the voucher's batch and links the two, as a void does (tier 1). From APPROVED or QUEUED_FOR_CHECKOUT the clinic's balance was credited but nothing was sent to Stripe: it reverses that credit and credits the distributor's allocation back as one ALLOCATION transaction, and the batch releases the voucher's slot (tier 2). A PAID voucher is refused with 409, because recovering money already sent needs a payout clawback, which does not exist; so is a voucher in any other state, or a clinic balance that does not cover the reversal. Gated on execute:InvalidateVoucherCommand, a platform-only permission. The write runs as the caller at the DAL, which requires the same permission and records who invalidated it.
Arguments
| Argument | Type | Description | |
|---|---|---|---|
idpath | string (uuid) | required | Voucher id. |
bodyJSON | object | required | The request body, as a JSON object. Its fields are listed below. |
Fields of body
| Field | Type | Description | |
|---|---|---|---|
reason | string | required | Why the voucher is invalidated. Required and recorded on the voucher. |
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.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "post_vouchers_by_id_invalidate",
"arguments": {
"id": "11111111-1111-4111-8111-111111111111",
"body": {
"reason": "string"
}
}
}
}Result
On success (HTTP 200) the tool returns one text item holding the API's JSON, pretty-printed.
The voucher was invalidated; tier says which way its value went back.
{
"claimedByOrgId": "11111111-1111-4111-8111-111111111111",
"currency": "string",
"distributorOrgId": "11111111-1111-4111-8111-111111111111",
"event": {
"aggregateId": "string",
"aggregateType": "string",
"eventId": "string",
"eventType": "string",
"timestamp": 1
},
"replacedByVoucherId": "11111111-1111-4111-8111-111111111111",
"reversedAmount": 1,
"state": "ACTIVE",
"tier": 1,
"transactionId": "11111111-1111-4111-8111-111111111111",
"voucherId": "11111111-1111-4111-8111-111111111111"
}Fields
| Field | Type | Description |
|---|---|---|
claimedByOrgId | string (uuid) | null | The clinic that had taken the voucher. |
currency | string | |
distributorOrgId | string (uuid) | null | Tier 2 only — the distributor whose allocation was credited back. |
event | object | |
event.aggregateId | string | |
event.aggregateType | string | |
event.eventId | string | |
event.eventType | string | |
event.timestamp | number | |
replacedByVoucherId | string (uuid) | null | Tier 1 only — the replacement minted into the batch. |
reversedAmount | integer | Tier 2 only — CENTS reversed from the clinic's balance; 0 for tier 1. |
state | "ACTIVE" | "APPROVED" | "ASSIGNED" | "AVAILABLE" | "CLAIMED" | "CREATED" | … (17 values) | A voucher's lifecycle state, as the DAL's VoucherState enum names it. |
tier | 1 | 2 | 1 when a replacement was minted, 2 when a credit was reversed. |
transactionId | string (uuid) | null | Tier 2 only — the ledger transaction recording the reversal. |
voucherId | string (uuid) |
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.
400The reason is missing, blank or not a string, or the id is not a UUID.
403Authenticated, but the caller holds none of the required permissions.
404No such resource — or none this caller may see.
409The resource is not in a state that allows this operation.
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.
{
"name": "post_vouchers_by_id_invalidate",
"description": "POST /api/vouchers/{id}/invalidate — Undoes a clinic's claim on a voucher and returns its value to the pool it came from. The DAL decides how from the voucher's current state, in one write. From VERIFIED, PERFORMED_PENDING_CLAIM or CLAIMED no money has moved: it mints a same-value CREATED replacement into the voucher's batch and links the two, as a void does (tier 1). From APPROVED or QUEUED_FOR_CHECKOUT the clinic's balance was credited but nothing was sent to Stripe: it reverses that credit and credits the distributor's allocation back as one ALLOCATION transaction, and the batch releases the voucher's slot (tier 2). A PAID voucher is refused with 409, because recovering money already sent needs a payout clawback, which does not exist; so is a voucher in any other state, or a clinic balance that does not cover the reversal. Gated on `execute:InvalidateVoucherCommand`, a platform-only permission. The write runs as the caller at the DAL, which requires the same permission and records who invalidated it.\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",
"description": "Voucher id."
},
"body": {
"type": "string",
"description": "The JSON request body: { reason*: string (Why the voucher is invalidated.) }"
}
},
"required": [
"id",
"body"
]
},
"annotations": {
"readOnlyHint": false,
"destructiveHint": true,
"idempotentHint": false,
"openWorldHint": false
}
}