get_vouchers_by_id

Read-only

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

ArgumentTypeDescription
idpathstring (uuid)requiredVoucher 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.

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

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

FieldTypeDescription
adjudicationPolicyVersionstring | nullThe rules' policy version an AUTO approval was decided under; null for a MANUAL one.
approvalBasisobject | nullWhat 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.checksarray of objectEvery 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.invoiceSha256stringsha256 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.policyVersionstring
approvalBasis.proposedCentsintegerWhat the rules credited, in CENTS.
approvalModeobject | nullWho 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.
approvalRequiredboolean
approvedAtinteger | null
assignedToOrgIdstring (uuid) | nullThe org holding the voucher to distribute it — a distributor or the platform.
autoApprovalDecisionobject | nullThe 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.decidedAtinteger | nullWhen it was recorded, epoch MILLISECONDS.
autoApprovalDecision.decision"AUTO_APPROVE" | "HOLD"
autoApprovalDecision.holdReasonsarray 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.invoiceSha256string | nullsha256 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.policyVersionstring
autoApprovalDecision.proposedCentsinteger | nullWhat approval would credit, in CENTS, capped; null when the rules could not compute it.
batchIdstring (uuid) | null
claimAmountinteger | nullThe 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).
claimedAtinteger | nullWhen the clinic submitted its claim.
claimedByOrgIdstring (uuid) | nullThe 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.
codestring
createdAtinteger | null
creditedAmountinteger | nullCENTS approval credited the claiming clinic; null before approval.
currencystring
deletedboolean
expiresAtinteger
idstring (uuid)
issuedAtinteger | null
issuedToEmailstring | nullThe beneficiary's address — the reason this read is org-scoped.
issuedToPhonestring | null
issuedToUserIdstring | null
maxPayoutinteger | nullThe 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" | nullThe 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.
paidAtinteger | null
performedAtinteger | null
printStatus"NOT_PRINTED" | "PRINT_FAILED" | "SUBMITTED"Whether a printer has this voucher, apart from its lifecycle state.
procedurestring | null
procedureBoundboolean | null
receiptAmountinteger | nullThe invoice total the clinic entered, in CENTS — what it billed, not what PFF pays. Optional at upload.
receiptCheckFlagsarray of string | nullWhat 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.
receiptCheckLineItemsarray of object | nullEvery line the check read off the invoice. Empty when it read none; null when no reading is recorded.
receiptCheckLineItems[].amountCentsinteger | nullCENTS; negative for a discount line; null when the amount could not be read.
receiptCheckLineItems[].coveredbooleanWhether the check judged the line part of the procedure or its supporting costs — what PFF pays.
receiptCheckLineItems[].descriptionstring
receiptCheckReasonstring | nullThe 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.
receiptCurrencystring | null
receiptFilenamestring | null
receiptSha256string | nullsha256 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.
receiptUploadedAtinteger | null
receiptUristring | nullThe stored invoice's s3:// URI. A browser cannot fetch it — GET /api/vouchers/{id}/receipt links it.
receiptValidatedAmountinteger | nullThe 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.
replacedByVoucherIdstring (uuid) | null
replacesVoucherIdstring (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.

403

The caller is not platform staff and holds a voucher feature in no organization.

404

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

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