post_vouchers_by_id_void
Calls POST /api/vouchers/{id}/void as the signed-in person · REST reference
Void a voucher
Moves the voucher to VOIDED through the state machine, which allows it only while no clinic has taken it — CREATED, ASSIGNED or ISSUED. A voucher IN PROCESS (a clinic took it and it is not yet paid) moves only along its claim, and is refused with 409, as is one already PAID, VOIDED or EXPIRED. Gated on execute:RevokeVoucherCommand. A voucher in a batch is REPLACED in that batch in the same write — the DAL mints one CREATED voucher like it and links the two (replacedByVoucherId on the voided one, returned here) — unless the batch's own expiry has already passed. That holds for any void, through either route.
Arguments
| Argument | Type | Description | |
|---|---|---|---|
idpath | string (uuid) | required | Voucher id. |
bodyJSON | object | The request body, as a JSON object. Its fields are listed below. |
Fields of body
| Field | Type | Description | |
|---|---|---|---|
reason | string | Recorded as the void reason. Omitted or empty defaults to the literal 'Voided by operator'. |
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_void",
"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 voided voucher, as the DAL's TransitionVoucher selection returns it; its replacedByVoucherId names the replacement when the DAL minted one.
{
"code": "string",
"currency": "string",
"expiresAt": 1,
"id": "11111111-1111-4111-8111-111111111111",
"state": "ACTIVE",
"value": 1,
"assignedToOrgId": "11111111-1111-4111-8111-111111111111",
"batchId": "11111111-1111-4111-8111-111111111111",
"issuedAt": 1,
"issuedToEmail": "string",
"issuedToPhone": "string",
"maxPayout": 1,
"procedure": "string",
"replacedByVoucherId": "11111111-1111-4111-8111-111111111111"
}Fields
| Field | Type | Description |
|---|---|---|
assignedToOrgId | string (uuid) | null | |
batchId | string (uuid) | null | |
code | string | |
currency | string | |
expiresAt | integer | Epoch MILLISECONDS. |
id | string (uuid) | |
issuedAt | integer | null | Epoch MILLISECONDS. |
issuedToEmail | string | null | |
issuedToPhone | string | null | |
maxPayout | integer | null | Catalog face-value cap in CENTS. |
procedure | string | null | |
replacedByVoucherId | string (uuid) | null | The voucher the DAL minted to replace this one in its batch, if any. |
serviceType | string | null | |
species | string | null | |
state | "ACTIVE" | "APPROVED" | "ASSIGNED" | "AVAILABLE" | "CLAIMED" | "CREATED" | … (17 values) | A voucher's lifecycle state, as the DAL's VoucherState enum names it. |
value | integer | Face value in CENTS. |
voidReason | string | null |
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 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_void",
"description": "POST /api/vouchers/{id}/void — Moves the voucher to VOIDED through the state machine, which allows it only while no clinic has taken it — CREATED, ASSIGNED or ISSUED. A voucher IN PROCESS (a clinic took it and it is not yet paid) moves only along its claim, and is refused with 409, as is one already PAID, VOIDED or EXPIRED. Gated on `execute:RevokeVoucherCommand`. A voucher in a batch is REPLACED in that batch in the same write — the DAL mints one CREATED voucher like it and links the two (`replacedByVoucherId` on the voided one, returned here) — unless the batch's own expiry has already passed. That holds for any void, through either route.\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 (Recorded as the void reason.) }"
}
},
"required": [
"id"
]
},
"annotations": {
"readOnlyHint": false,
"destructiveHint": true,
"idempotentHint": false,
"openWorldHint": false
}
}