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

  1. pink.check_policy (optional) · dry run, nothing is held.
  2. pink.request_payment · decision now: allowed with a credential, pending_human with a hold_id, or blocked.
  3. pink.get_credential(hold_id) · poll while a person decides; returns the credential on approval, or declined / expired.
  4. 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

FieldTypeMeaning
payee_idstringId from pink.list_payees. Omit for a payee not on the list.
payee_namestringName of the payee. Required if payee_id is omitted.
amount *numberAmount in the payment currency
currencyenum: USD, EUR, GBP, HKD, SGD, JPY
purpose *stringWhat this payment is for, in one line (shown to approvers)
reasonstringWhy you are making it now: the data you saw, the threshold that triggered it (shown to approvers)
evidencearray of stringReferences you can attach: PO number, invoice id, ticket id, statement id, photos
evidence_flagsarray of enum: po, sow, ticket, scan, statement, brief, renewal, dupInvoice, payeeChanged, repeatCustomer, depositStructured 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_hourintegerLocal 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

FieldTypeMeaning
payee_idstringId from pink.list_payees. Omit for a payee not on the list.
payee_namestringName of the payee. Required if payee_id is omitted.
amount *numberAmount in the payment currency
currencyenum: USD, EUR, GBP, HKD, SGD, JPY
purpose *stringWhat this payment is for, in one line (shown to approvers)
reasonstringWhy you are making it now: the data you saw, the threshold that triggered it (shown to approvers)
evidencearray of stringReferences you can attach: PO number, invoice id, ticket id, statement id, photos
evidence_flagsarray of enum: po, sow, ticket, scan, statement, brief, renewal, dupInvoice, payeeChanged, repeatCustomer, depositStructured 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_hourintegerLocal hour of day (0-23) for time-of-day rules. Defaults to UTC hour.
idempotency_keystringAny 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

FieldTypeMeaning
hold_id *stringThe 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

FieldTypeMeaning
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

CallAllowedNeeds a personStopped
check_policywould_allowwould_askwould_block
request_paymentallowedpending_humanblocked
get_credential after a person decidesapprovedpending_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": "…"
  }
}