get_vouchers_by_id
Calls GET /api/vouchers/{id} as the signed-in person · REST reference
Get one voucher by id, org-scoped
Returns the full voucher record, INCLUDING the beneficiary's issuedToEmail, so it is org-scoped: platform staff may read any voucher, and everyone else only a voucher whose assignedToOrgId or claimedByOrgId is an org in which it holds a voucher feature (the set GET /api/vouchers names; both, so a clinic keeps reading the voucher through the whole claim). A caller holding a voucher feature in no organization is refused 403 before any lookup. The claiming clinic's invoice is read only by platform staff and that clinic: to the org holding the voucher, what the invoice says and what the claim auto-approval rules decided on it answer null (see VoucherDetail), and the rules' trail is not read for it. A CLAIMED voucher's reader who may see the invoice is answered the rules' latest decision, read off the trail; a trail that cannot be read answers 503, never a claim shown as undecided. ALL THREE "no such voucher for you" cases answer an IDENTICAL 404 — the id is not UUID-shaped, no voucher has it, or it belongs to another org. The cross-org case is 404 rather than the claim steps' 403 on purpose: a 403 would confirm that a given id names a real voucher, which is enough to enumerate the estate one id at a time. The UUID check also stops an unmatched literal path (e.g. /api/vouchers/catalog) being captured here and sent to the DAL as an id.
Arguments
| Argument | Type | Description | |
|---|---|---|---|
idpath | string (uuid) | required | Voucher id. A non-UUID value answers 404 without touching the DAL. |
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": "get_vouchers_by_id",
"arguments": {
"id": "11111111-1111-4111-8111-111111111111"
}
}
}Result
On success (HTTP 200) the tool returns one text item holding the API's JSON, pretty-printed.
The voucher, with the value of its claim (claimAmount) and what the claim auto-approval rules decided on it (approvalBasis, autoApprovalDecision).
{
"approvalBasis": {
"checks": [
{}
],
"invoiceSha256": "string",
"policyVersion": "string",
"proposedCents": 1
},
"approvalRequired": true,
"autoApprovalDecision": {
"decidedAt": 1,
"decision": "AUTO_APPROVE",
"holdReasons": [
"READABLE"
],
"invoiceSha256": "string",
"mode": "SHADOW",
"policyVersion": "string",
"proposedCents": 1
},
"claimAmount": 1,
"clawbackStatus": "REQUESTED",
"code": "string",
"currency": "string",
"deleted": true,
"expiresAt": 1,
"id": "11111111-1111-4111-8111-111111111111",
"openClawbackStatus": "REQUESTED",
"printStatus": "NOT_PRINTED",
"state": "ACTIVE",
"value": 1
}Fields
| Field | Type | Description |
|---|---|---|
adjudicationPolicyVersion | string | null | The rules' policy version an AUTO approval was decided under; null for a MANUAL one. |
approvalBasis | object | null | What an AUTO approval was decided on. Null for a MANUAL one, before approval, and when what is stored is not a basis the rules write. |
approvalBasis.checks | array of object | Every check, in the order the rules ran them. |
approvalBasis.checks[].id | "READABLE" | "ARITHMETIC" | "ENTERED_TOTAL" | "NO_INJECTION" | "LINES_CLASSIFIED" | "CORE_PROCEDURE" | … (14 values) | One of the rules' checks, named for what it confirms. A check that fails holds the claim for a person; none denies it. |
approvalBasis.checks[].outcome | "PASS" | "NA" | |
approvalBasis.invoiceSha256 | string | sha256 of the invoice the rules read, as 64 lowercase hex characters — the voucher's receiptSha256 when it was approved, which the approval was bound to. |
approvalBasis.policyVersion | string | |
approvalBasis.proposedCents | integer | What the rules credited, in CENTS. |
approvalMode | object | null | Who approved the claim: the auto-approval rules (AUTO), with no person, or a person (MANUAL). Null before approval, and on a claim approved before the mode was recorded. |
approvalRequired | boolean | |
approvedAt | integer | null | |
assignedToOrgId | string (uuid) | null | The org holding the voucher to distribute it — a distributor or the platform. |
autoApprovalDecision | object | null | The rules' latest decision while the claim waits (CLAIMED), made on the invoice on file. Null in every other state, and when no pass has decided the invoice on file — the mode is OFF, the invoice check has not answered, or the clinic filed another invoice since. |
autoApprovalDecision.decidedAt | integer | null | When it was recorded, epoch MILLISECONDS. |
autoApprovalDecision.decision | "AUTO_APPROVE" | "HOLD" | |
autoApprovalDecision.holdReasons | array of "READABLE" | "ARITHMETIC" | "ENTERED_TOTAL" | "NO_INJECTION" | "LINES_CLASSIFIED" | "CORE_PROCEDURE" | … (14 values) | The checks that held the claim, in the rules' order; empty for AUTO_APPROVE. |
autoApprovalDecision.invoiceSha256 | string | null | sha256 of the invoice it was made on — the voucher's receiptSha256. |
autoApprovalDecision.mode | "SHADOW" | "ENFORCE" | The mode the pass was in. In SHADOW the rules approve nothing, so an AUTO_APPROVE says what ENFORCE would have done. |
autoApprovalDecision.policyVersion | string | |
autoApprovalDecision.proposedCents | integer | null | What approval would credit, in CENTS, capped; null when the rules could not compute it. |
batchId | string (uuid) | null | |
claimAmount | integer | null | The value of the voucher's claim in CENTS — the only money a voucher is shown as worth, derived by the backend (claimAmount, backend/src/domain/claimInvoice.ts), not a DAL field. Null until the claim is submitted, and while a CLAIMED voucher's invoice waits on the AI or a reviewer; a CLAIMED voucher's validated covered amount, capped as approval caps it; from APPROVED on, what approval credited (creditedAmount). Never the face value (value). |
claimedAt | integer | null | When the clinic submitted its claim. |
claimedByOrgId | string (uuid) | null | The clinic that took the voucher at verify — the one its claim pays. |
clawbackStatus | "REQUESTED" | "APPROVED" | "EXECUTING" | "RECOVERED" | "PARTIALLY_RECOVERED" | "WRITTEN_OFF" | … (7 values) | The status of the latest payout clawback against a voucher, resolved ones included — what the voucher's (or its payout's) clawback chip says. Null when there is none. DENIED is never reported, nor a REQUESTED clawback Pawsitive Future filed: until it is approved it is Pawsitive Future's own deliberation. |
code | string | |
createdAt | integer | null | |
creditedAmount | integer | null | CENTS approval credited the claiming clinic; null before approval. |
currency | string | |
deleted | boolean | |
expiresAt | integer | |
id | string (uuid) | |
issuedAt | integer | null | |
issuedToEmail | string | null | The beneficiary's address — the reason this read is org-scoped. |
issuedToPhone | string | null | |
issuedToUserId | string | null | |
maxPayout | integer | null | The most this voucher pays, in CENTS, when it has a catalog cap; else value is the cap. |
openClawbackStatus | "REQUESTED" | "APPROVED" | "EXECUTING" | "PARTIALLY_RECOVERED" | "WRITTEN_OFF" | null | The status of the voucher's open payout clawback, newest first: one being decided or collected, or one closed without all of its cash whose payouts pause has not been lifted. Null when none is — and for any voucher that is not PAID. A REQUESTED clawback Pawsitive Future filed is not reported: until it is approved it is Pawsitive Future's own deliberation. |
paidAt | integer | null | |
performedAt | integer | null | |
printStatus | "NOT_PRINTED" | "PRINT_FAILED" | "SUBMITTED" | Whether a printer has this voucher, apart from its lifecycle state. |
procedure | string | null | |
procedureBound | boolean | null | |
receiptAmount | integer | null | The invoice total the clinic entered, in CENTS — what it billed, not what PFF pays. Optional at upload. |
receiptCheckFlags | array of string | null | What the check flagged. INJECTION_SUSPECTED, LOW_CONFIDENCE and UNREADABLE_TOTAL are why it routed the claim to a reviewer (PENDING_MANUAL_REVIEW). OVER_CAP is raised on a VALID verdict, when the covered total exceeds the voucher's catalog cap, and only records that: approval credits at most the cap. Empty when it raised none; null when no reading is recorded. |
receiptCheckLineItems | array of object | null | Every line the check read off the invoice. Empty when it read none; null when no reading is recorded. |
receiptCheckLineItems[].amountCents | integer | null | CENTS; negative for a discount line; null when the amount could not be read. |
receiptCheckLineItems[].covered | boolean | Whether the check judged the line part of the procedure or its supporting costs — what PFF pays. |
receiptCheckLineItems[].description | string | |
receiptCheckReason | string | null | The invoice check's one-line reason for its verdict. Null until a verdict is recorded, and on a claim checked before the check's reading was kept. |
receiptCurrency | string | null | |
receiptFilename | string | null | |
receiptSha256 | string | null | sha256 of the invoice on file, as 64 lowercase hex characters — what a reviewer's approval names back as expectedInvoiceSha256 (POST /api/claims/{id}/approve), so an invoice filed after the reviewer read this one is refused rather than paid. Null for an invoice filed before hashes were stored, and before any invoice is filed. |
receiptUploadStatus | "STORED" | "PENDING_UPLOAD" | STORED when the PDF is in storage; PENDING_UPLOAD when the upload never reached it. |
receiptUploadedAt | integer | null | |
receiptUri | string | null | The stored invoice's s3:// URI. A browser cannot fetch it — GET /api/vouchers/{id}/receipt links it. |
receiptValidatedAmount | integer | null | The covered amount (the procedure and its supporting costs) the AI read off the invoice, in CENTS. |
receiptValidationStatus | "PENDING" | "VALID" | "PENDING_MANUAL_REVIEW" | The AI's verdict on the invoice. VALID carries receiptValidatedAmount; PENDING_MANUAL_REVIEW means approval needs a reviewer's amount. There are no denials. |
replacedByVoucherId | string (uuid) | null | |
replacesVoucherId | string (uuid) | null |
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.
403The caller is not platform staff and holds a voucher feature in no organization.
404No such resource — or none this caller may see.
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": "get_vouchers_by_id",
"description": "GET /api/vouchers/{id} — Returns the full voucher record, INCLUDING the beneficiary's `issuedToEmail`, so it is org-scoped: platform staff may read any voucher, and everyone else only a voucher whose `assignedToOrgId` or `claimedByOrgId` is an org in which it holds a voucher feature (the set `GET /api/vouchers` names; both, so a clinic keeps reading the voucher through the whole claim). A caller holding a voucher feature in no organization is refused 403 before any lookup. The claiming clinic's invoice is read only by platform staff and that clinic: to the org holding the voucher, what the invoice says and what the claim auto-approval rules decided on it answer null (see `VoucherDetail`), and the rules' trail is not read for it. A CLAIMED voucher's reader who may see the invoice is answered the rules' latest decision, read off the trail; a trail that cannot be read answers 503, never a claim shown as undecided. ALL THREE \"no such voucher for you\" cases answer an IDENTICAL 404 — the id is not UUID-shaped, no voucher has it, or it belongs to another org. The cross-org case is 404 rather than the claim steps' 403 on purpose: a 403 would confirm that a given id names a real voucher, which is enough to enumerate the estate one id at a time. The UUID check also stops an unmatched literal path (e.g. /api/vouchers/catalog) being captured here and sent to the DAL as an id.",
"inputSchema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Voucher id. A non-UUID value answers 404 without touching the DAL."
}
},
"required": [
"id"
]
},
"annotations": {
"readOnlyHint": true,
"openWorldHint": false
}
}