Paystack ships as a Model Context Protocol server plus a REST API. Everything is typed. Every call carries a ReasoningLog. Every state change is signed.
# Claude Desktop · Cursor · any MCP client
mcp install codelucent/paystack
# or: self-hosted
docker run -p 7022:7022 \
-e PAYSTACK_API_KEY=psk_live_... \
ghcr.io/codelucent/paystack-mcp:latestThe API is small on purpose. Each verb has a clear posture, clear scope, and a documented risk level. Most agents only need two: initiate_escrow_payout and reverse_escrow.
| Tool | Purpose | Risk |
|---|---|---|
| initiate_escrow_payout | Hold funds against a counter-party. Emits VFP, state=held. | medium |
| release_escrow | Release held funds before the buffer elapses. Rarely used. | high · requiresApproval |
| reverse_escrow | Pull back a held escrow. Safe, reversible, operator-approved. | low |
| refund_released | Vendor-initiated return after release. Creates a linked entry. | low |
| list_pending | Enumerate held escrows in operator scope. Read-only. | read |
| set_limit | Adjust per-agent autonomy ceiling. Operator scope only. | high · requiresApproval |
| verify_vfp | Public endpoint. Returns state, amount, buffer progress for any VFP. | public |
{
"name": "initiate_escrow_payout",
"description": "Hold funds in the custodial buffer against a counter-party. Returns a VFP.",
"requiresApproval": false,
"input": {
"amount_cents": "integer",
"counter_party": "string",
"priority": "'instant' | 'disputable' | 'scheduled'",
"audit_window": "duration?",
"reasoning": "ReasoningEnvelope"
},
"output": {
"vfp": "string",
"state": "'held'",
"releases_at": "iso8601"
}
}Every agent-triggered payment includes a ReasoningEnvelope. It travels with the ledger entry and through webhooks. Finance, compliance, and engineering all read the same field — no after-the-fact reconstruction.
type ReasoningEnvelope = {
// Why the agent chose to act
policy: string // dotted policy path (e.g. 'maintenance.repair')
confidence: number // [0, 1]
agent_id: string // stable id for the acting agent
model: string // model version that authorized
// Evidence
inputs_hash: sha256 // hash of the prompt/context that produced this
citations: string[]? // source ids the agent grounded on
tool_trace: string[]? // upstream tool calls that led here
// Operator overrides
approved_by: string? // operator id if human-in-the-loop fired
override: boolean? // true if policy would have blocked
}// Webhook payload — POST to your endpoint
{
"type": "escrow.released",
"vfp": "VFP-7D4C-11A2",
"amount_cents": 120000,
"counter_party": "acme-roofing-llc",
"reasoning": { ... }, // the original envelope
"ledger_entry": "0192f3a7-...",
"signature": "ed25519:..." // verify against pubkey from trust center
}