Payroll
Draft a pay run; recipients add their own destination afterwards. Nothing is funded or paid until you say so, explicitly, twice.
Concept
A pay run holds a list of items — one per recipient, each with an amount. Recipients you haven't paid before get their own hosted link to add a bank account or wallet address; you never collect or transmit their destination on their behalf.
Resources
| Object | What it is |
|---|---|
payroll_runs | The run itself — status, funding state, currency, recipient summary. |
payroll_run_items | One line per recipient — destination status, amount, per-item status. |
payroll_recipients | People you've paid before. The one write: save a destination the recipient submitted as their default. |
payroll_templates | A saved item list from a previous run, for building the next one faster. |
payroll_recipient_sessions | The recipient's own hosted page (public token) to add or confirm their destination. |
Lifecycle
reviewed → funding_pending → funded → executing → completed, with partial, failed and cancelled as terminal branches. funded never means fully funded — the funding classifier is a boolean gate, not a percentage.
Minimal flow
POST /v1/payroll_runs— draft it with recipients and amounts.GET /v1/payroll_runs/{id}/readiness— a preflight over the payer-compliance gateexecutechecks first (Bridge verification, KYC, ToS, rail endorsement), without executing anything. Aready: trueanswer does not by itself guaranteeexecutesucceeds — funding, destinations and rail resolution are checked separately, at the mutation.POST .../approve, then fund it (bank or crypto funding instructions).POST .../execute— REST-only, the money boundary. This is the one step no MCP tool performs.GET /v1/payroll_runs/{id}or the MCP toolget_payroll_runto watch it complete.
Caps, always checked twice
$25,000 per run, $10,000 per item, 500 rows per run — enforced at both create and execute, so a run that was valid when drafted can still be refused at execute if something about the account changed in between.
When a recipient saves a destination
A destination the recipient saves through their own link pays that run's row right away. It does not become their default on its own: it waits on the recipient as pending_destination (masked — asset, network or rail, country, last four), and new runs keep asking until you save it.
GET /v1/payroll_recipients— a recipient with a non-nullpending_destinationhas answered. Show the masked destination.POST /v1/payroll_recipients/{id}/adopt_pending_destinationwith{"expected_submitted_at": "<pending_destination.submitted_at>"}. It saves the destination as the default and fills this recipient's rows that still wait for a destination in runs not yet approved —updated_run_itemslists them. A row the destination cannot pay (another currency) keeps asking the recipient and is listed inskipped_run_items.409 pending_destination_changed— the recipient saved another destination after you read it. Their default is unchanged: read the recipient again and show the new one before you save it. In a rare race — the recipient saves a new destination while your call runs — rows your call already filled with the destination you confirmed keep it; the next read of those runs shows them.
Moves no money. A Swaps Wallet address on a network other than Tempo, which nothing can sign for, is refused 422 destination_rail_keyless before anything is written. There is no MCP tool for this step: it changes where future payouts go, so a person confirms it.
What an agent can and cannot do here
prepare_payroll_run drafts a run for review — it never collects bank or wallet details itself, and it never funds or executes anything. execute has no MCP tool; running payroll is deliberately a REST-only, human-confirmed action, the same boundary payment link activation draws.
Next: the reference for the full run and item schemas · Conventions for how the fee (1%, employer-funded on top) shows up on the wire.