MCP tools reference
Sandbox live. Create a free sandbox workspace at agentic-sandbox.pinkwallet.com (test credentials only; no money moves). Production is not yet available.
Pink exposes seven tools over MCP (Streamable HTTP, stateless, JSON responses). The REST API mirrors them one to one. Every schema and every response on this page was captured from the live sandbox on 2026-10-01 for the coffee-shop template, acting as the Purchasing AI agent; keys are redacted.
Connection
Endpoint: POST https://agentic-sandbox.pinkwallet.com/mcp
Auth A: Authorization: Bearer <agent_key>
Auth B: POST https://agentic-sandbox.pinkwallet.com/mcp/<agent_key> (key in the path, for clients that cannot set headers)
GET/DELETE on the endpoint return 405: the server is stateless and opens no server-initiated stream.Server instructions returned at initialize tell the model how to use the tools; you do not need a system prompt for the payment flow, though you may add one.
The payment lifecycle in four calls
pink.check_policy(optional) · dry run, nothing is held.pink.request_payment· decision now:allowedwith a credential,pending_humanwith ahold_id, orblocked.pink.get_credential(hold_id)· poll while a person decides; returns the credential on approval, ordeclined/expired.pink.report_receipt· reconcile and raise the agent's trust score.
pink.get_budget
What this agent may still spend: monthly budget left, spent today, single-payment cap, vault balances, company daily ceiling.
Input
No inputs.
Example call
{}Response (live sandbox)
{
"agent": "Purchasing AI",
"status": "active",
"monthly_budget": 4000,
"spent_this_month": 2260,
"left_this_month": 1740,
"spent_today": 0,
"single_payment_cap": 500,
"vault": {
"id": "v_ops",
"name": "Operating",
"balances": {
"USD": 18420.55
}
},
"company_daily_ceiling": 6000,
"company_spent_today": 0,
"policy_version": 1
}pink.list_payees
Suppliers, platforms and contractors this company has approved. Paying anyone else stops and asks a person.
Input
No inputs.
Example call
{}Response (live sandbox)
{
"payees": [
{
"id": "p_cc",
"name": "Counter Culture Coffee",
"category": "supplier",
"paid_by": "bank",
"country": "US",
"currency": "USD",
"note": "Beans · net 15"
},
{
"id": "p_sysco",
"name": "Sysco",
"category": "supplier",
"paid_by": "card",
"country": "US",
"currency": "USD",
"note": "Milk, syrups, food"
},
{
"id": "p_uline",
"name": "Uline",
"category": "supplier",
"paid_by": "card",
"country": "US",
"currency": "USD",
"note": "Cups, lids, paper goods"
},
{
"id": "p_oatly",
"name": "Oatly Distribution",
"category": "supplier",
"paid_by": "bank",
"country": "US",
"currency": "USD",
"note": "Oat milk"
},
{
"…": "8 payees in the coffee template"
}
]
}pink.list_rules
The policy rules that apply to this agent, in evaluation order. First match decides: allow, ask, or block.
Input
No inputs.
Example call
{}Response (live sandbox)
{
"rules": [
{
"id": "r11",
"name": "Never: gift cards, cash-like, crypto",
"agents": "*",
"payee": "cat:blocked",
"amount": {
"min": 0,
"max": null,
"window": "tx"
},
"action": "block"
},
{
"id": "r1",
"name": "Between 11pm and 6am: ask the owner",
"agents": "*",
"payee": "any",
"amount": {
"min": 0,
"max": null,
"window": "tx"
},
"outside_hours": [
6,
23
],
"action": "ask",
"approvers": {
"people": [
"owner"
],
"n": 1,
"label": "Maya Chen (Owner)"
}
},
{
"id": "r2",
"name": "Payee changed bank details: ask the owner first",
"agents": "*",
"payee": "approved",
"amount": {
"min": 0,
"max": null,
"window": "tx"
},
"requires": "payeeChanged",
"action": "ask",
"approvers": {
"people": [
"owner"
],
"n": 1,
"label": "Maya Chen (Owner)"
}
},
{
"…": "7 rules apply to this agent"
}
]
}pink.check_policy
Dry run. Returns would_allow / would_ask / would_block with the rule and the full decision trace. Nothing is spent or held.
Input
| Field | Type | Meaning |
|---|---|---|
payee_id | string | Id from pink.list_payees. Omit for a payee not on the list. |
payee_name | string | Name of the payee. Required if payee_id is omitted. |
amount * | number | Amount in the payment currency |
currency | enum: USD, EUR, GBP, HKD, SGD, JPY | |
purpose * | string | What this payment is for, in one line (shown to approvers) |
reason | string | Why you are making it now: the data you saw, the threshold that triggered it (shown to approvers) |
evidence | array of string | References you can attach: PO number, invoice id, ticket id, statement id, photos |
evidence_flags | array of enum: po, sow, ticket, scan, statement, brief, renewal, dupInvoice, payeeChanged, repeatCustomer, deposit | Structured evidence and signals: po (matching purchase order), sow (signed SOW), ticket (helpdesk ticket), scan (warehouse scan), statement (matches carrier/cloud statement), brief (signed creator brief), renewal (within 10% of last invoice), dupInvoice, payeeChanged, repeatCustomer, deposit |
local_hour | integer | Local hour of day (0-23) for time-of-day rules. Defaults to UTC hour. |
Example call
{
"payee_id": "p_cc",
"amount": 420,
"purpose": "20 kg espresso beans"
}Response (live sandbox)
{
"decision": "would_allow",
"reason": "Small supply orders go through",
"rule": {
"id": "r4",
"name": "Small supply orders go through",
"agents": [
"a_purch",
"a_inv"
],
"payee": "approved",
"amount": {
"min": 0,
"max": 500,
"window": "tx"
},
"action": "allow"
},
"policy_version": 1,
"trace": [
"PASS · Agent registered · Purchasing AI",
"PASS · Agent active · not paused",
"PASS · Monthly budget · $2,680 of $4,000 after this",
"PASS · Daily ceiling, all agents · $420 of $6,000",
"PASS · Vault balance · Operating · $18,420.55 available",
"SKIP · Never: gift cards, cash-like, crypto · payee out of scope",
"SKIP · Between 11pm and 6am: ask the owner · inside business hours (06:00–23:00)",
"SKIP · Payee changed bank details: ask the owner first · no payee bank details changed in the last 7 days",
"SKIP · Payroll runs on schedule · different agent",
"PASS · Small supply orders go through · matched · allow"
]
}pink.request_payment
The real call. Returns "allowed" with a single-use credential, "pending_human" with a hold_id while a person is asked, or "blocked" with the reason. Pass idempotency_key to make retries safe.
Input
| Field | Type | Meaning |
|---|---|---|
payee_id | string | Id from pink.list_payees. Omit for a payee not on the list. |
payee_name | string | Name of the payee. Required if payee_id is omitted. |
amount * | number | Amount in the payment currency |
currency | enum: USD, EUR, GBP, HKD, SGD, JPY | |
purpose * | string | What this payment is for, in one line (shown to approvers) |
reason | string | Why you are making it now: the data you saw, the threshold that triggered it (shown to approvers) |
evidence | array of string | References you can attach: PO number, invoice id, ticket id, statement id, photos |
evidence_flags | array of enum: po, sow, ticket, scan, statement, brief, renewal, dupInvoice, payeeChanged, repeatCustomer, deposit | Structured evidence and signals: po (matching purchase order), sow (signed SOW), ticket (helpdesk ticket), scan (warehouse scan), statement (matches carrier/cloud statement), brief (signed creator brief), renewal (within 10% of last invoice), dupInvoice, payeeChanged, repeatCustomer, deposit |
local_hour | integer | Local hour of day (0-23) for time-of-day rules. Defaults to UTC hour. |
idempotency_key | string | Any unique string per payment attempt. Repeating a key returns the original decision instead of paying twice. |
Example call
{
"payee_id": "p_cc",
"amount": 420,
"purpose": "20 kg espresso beans",
"reason": "Bean bin sensor at 18%; usual Monday order.",
"evidence": [
"Supplier quote Q-2291"
],
"idempotency_key": "order-2291"
}Response (live sandbox)
{
"payment_id": "pay_5db2539500ec",
"decision": "allowed",
"agent": "Purchasing AI",
"payee": "Counter Culture Coffee",
"payee_id": "p_cc",
"amount": 420,
"currency": "USD",
"purpose": "20 kg espresso beans",
"rule": "Small supply orders go through",
"policy_version": 1,
"created_at": "2026-10-01T16:38:59.953Z",
"credential": {
"type": "bank_transfer",
"sandbox": true,
"max_amount": 420,
"currency": "USD",
"locked_to": "Counter Culture Coffee",
"single_use": true,
"expires_at": "2026-10-01T16:53:59.953Z",
"transfer": {
"rail": "ACH",
"reference": "PWS-E35DFB73",
"status": "submitted"
}
}
}pink.get_credential
Check a pending payment. When a person approves, this returns the credential. Also works for any payment_id.
Input
| Field | Type | Meaning |
|---|---|---|
hold_id * | string | The hold_id / payment_id returned by pink.request_payment |
Example call
{
"hold_id": "pay_71995ad5222f"
}Response (live sandbox)
{
"payment_id": "pay_71995ad5222f",
"decision": "approved",
"agent": "Purchasing AI",
"payee": "Sysco",
"payee_id": "p_sysco",
"amount": 890,
"currency": "USD",
"purpose": "Weekly milk, syrups, pastries",
"rule": "Bigger supply orders: store manager checks",
"policy_version": 1,
"created_at": "2026-10-01T16:39:00.045Z",
"credential": {
"type": "virtual_card",
"sandbox": true,
"max_amount": 890,
"currency": "USD",
"locked_to": "Sysco",
"single_use": true,
"expires_at": "2026-10-01T16:54:00.301Z",
"card": {
"pan": "4111 1111 9566 9359",
"exp": "12/27",
"cvv": "663",
"name": "PINK SANDBOX"
}
},
"approved_by": [
"Sandbox admin"
]
}pink.report_receipt
After paying, file the receipt or invoice so the payment is reconciled and your trust score goes up.
Input
| Field | Type | Meaning |
|---|---|---|
payment_id * | string | |
receipt * | object |
Example call
{
"payment_id": "pay_5db2539500ec",
"receipt": {
"merchant": "Counter Culture Coffee",
"total": 420,
"currency": "USD",
"reference": "INV-10442"
}
}Response (live sandbox)
{
"ok": true,
"payment_id": "pay_5db2539500ec",
"trust_score": 96
}Decision strings, side by side
| Call | Allowed | Needs a person | Stopped |
|---|---|---|---|
check_policy | would_allow | would_ask | would_block |
request_payment | allowed | pending_human | blocked |
get_credential after a person decides | approved | pending_human (still waiting) | declined or expired |
The three other responses
pending_human
{
"payment_id": "pay_71995ad5222f",
"decision": "pending_human",
"agent": "Purchasing AI",
"payee": "Sysco",
"payee_id": "p_sysco",
"amount": 890,
"currency": "USD",
"purpose": "Weekly milk, syrups, pastries",
"rule": "Bigger supply orders: store manager checks",
"policy_version": 1,
"created_at": "2026-10-01T16:39:00.045Z",
"hold_id": "pay_71995ad5222f",
"approvers_needed": 1,
"approvals_so_far": 0,
"who": "Luis Ortega (Store manager)",
"expires_at": "2026-10-01T17:09:00.045Z",
"poll": "pink.get_credential(hold_id) · or GET /v1/payments/{id}"
}blocked
{
"payment_id": "pay_d30e3f506dbe",
"decision": "blocked",
"agent": "Purchasing AI",
"payee": "giftcards.com",
"payee_id": null,
"amount": 250,
"currency": "USD",
"purpose": "Customer giveaway prizes",
"rule": "Never: gift cards, cash-like, crypto",
"policy_version": 1,
"created_at": "2026-10-01T16:39:00.143Z",
"credential": null,
"retry_after": null,
"why": "matched · block"
}get_credential while still pending
{
"payment_id": "pay_71995ad5222f",
"decision": "pending_human",
"agent": "Purchasing AI",
"payee": "Sysco",
"payee_id": "p_sysco",
"amount": 890,
"currency": "USD",
"purpose": "Weekly milk, syrups, pastries",
"rule": "Bigger supply orders: store manager checks",
"policy_version": 1,
"created_at": "2026-10-01T16:39:00.045Z",
"hold_id": "pay_71995ad5222f",
"approvers_needed": 1,
"approvals_so_far": 0,
"who": "Luis Ortega (Store manager)",
"expires_at": "2026-10-01T17:09:00.045Z",
"poll": "pink.get_credential(hold_id) · or GET /v1/payments/{id}"
}Credential shapes
Three types, chosen by how the payee is paid. All are single-use, locked to the payee and amount, and expire 15 minutes after issue. In the sandbox they are test values (4111… cards, PWS- transfer references).
{
"virtual_card": {
"type": "virtual_card",
"card": {
"pan": "4111 1111 •••• ••••",
"exp": "12/27",
"cvv": "•••",
"name": "PINK SANDBOX"
},
"max_amount": 300,
"currency": "USD",
"locked_to": "Meta Ads",
"single_use": true,
"expires_at": "…"
},
"bank_transfer": {
"type": "bank_transfer",
"sandbox": true,
"max_amount": 420,
"currency": "USD",
"locked_to": "Counter Culture Coffee",
"single_use": true,
"expires_at": "2026-10-01T16:53:59.953Z",
"transfer": {
"rail": "ACH",
"reference": "PWS-E35DFB73",
"status": "submitted"
}
},
"platform_refund": {
"type": "platform_refund",
"platform": {
"name": "Stripe (refunds)",
"reference": "ref_…"
},
"max_amount": 64,
"currency": "USD",
"locked_to": "Stripe (refunds)",
"single_use": true,
"expires_at": "…"
}
}





