post_vouchers_by_id_invalidate

Changes data · you confirm first

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

ArgumentTypeDescription
idpathstring (uuid)requiredVoucher id.
bodyJSONobjectrequiredThe request body, as a JSON object. Its fields are listed below.

Fields of body

FieldTypeDescription
reasonstringrequiredWhy 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.

json
{
  "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"
      }
    }
  }
}
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 voucher was invalidated; tier says which way its value went back.

json
{
  "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

FieldTypeDescription
claimedByOrgIdstring (uuid) | nullThe clinic that had taken the voucher.
currencystring
distributorOrgIdstring (uuid) | nullTier 2 only — the distributor whose allocation was credited back.
eventobject
event.aggregateIdstring
event.aggregateTypestring
event.eventIdstring
event.eventTypestring
event.timestampnumber
replacedByVoucherIdstring (uuid) | nullTier 1 only — the replacement minted into the batch.
reversedAmountintegerTier 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.
tier1 | 21 when a replacement was minted, 2 when a credit was reversed.
transactionIdstring (uuid) | nullTier 2 only — the ledger transaction recording the reversal.
voucherIdstring (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.

400

The reason is missing, blank or not a string, or the id is not a UUID.

403

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

404

No such resource — or none this caller may see.

409

The 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.

json
{
  "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
  }
}