---
name: vurto-payments
description: Get paid and pay invoices with Vurto Payments (swap.vurto.cc), with wallet screening on both sides and the paid wallet analyses (Merkle Science, Scorechain). Use when an agent has to create an invoice, pay one from any token, ask for the paid analysis of the payer wallet (paid apart, at its price, by whoever asks for it on Solana or enabled EVM networks), or buy the paid analysis of the receiving wallet before paying. Works over MCP (https://swap.vurto.cc/mcp) or the HTTP API (https://swap.vurto.cc/v1).
---

# Vurto Payments for agents

Vurto Payments turns a wallet address into a payment request (an invoice) that anyone can pay with
any token of that network. Vurto checks **both wallets** before money moves, and can run a **paid
analysis** of a wallet (Merkle Science via Didit, the Scorechain sanctions list) when one side asks
for it. The live guide is `https://swap.vurto.cc/agent-api.md` (section 5.11 and 5.12); if this file
and the live API disagree, the live API wins.

Same tools on MCP and HTTP. `chainId` is an integer on EVM networks and the string
`"solana-mainnet"` on Solana. Solana addresses are base58 and case-sensitive: never change their case.

New invoices receive only verified dollar stablecoins on the network allowlist: USDC, USDT
(including USDT0), PYUSD, USDG and USD1 where supported. This restriction applies even without
paid analysis. New invoices carry no fee inside the payment: a paid analysis is paid apart, at its price. The payer may still use another
token through a swap. Previously created invoices keep their original token and payment terms.

## Who pays for each analysis (Solana and EVM networks with a split contract)

Each side pays the analysis it asks for, at the price of **one** wallet:

| Tool | Price per wallet |
| --- | --- |
| `merkle-science` | US$ 0.40 |
| `scorechain` | US$ 0.10 |
| both | US$ 0.50 |

- **The receiver** can ask for the analysis of the **payer** wallet, and pays its price apart before the invoice can be
  paid. The receiver gets the whole amount. Stablecoin invoices only (USDC, USDT, PYUSD, USDG, USD1).
- **The payer** can buy the analysis of the **receiving** wallet with their own money, before paying.
  Open and unpaid it does not hold the payment, so pay and report it first if you want its verdict to count.
- On EVM, check `invoiceSplit` in `GET /v1/chains`: `payerChecks` requires a configured
  split contract. The token allowlist differs by network: USDC and USDT on Base;
  USDC, USDT0, PYUSD and USDG on Arbitrum; USDC, USDT and USD1 on BNB;
  USDC, USDT0 and PYUSD on Polygon. USDT includes verified bridge versions.
  Never reuse an address from another network.

The free screening (OFAC list, issuer freezes, the money trail) always runs first. A wallet that
fails it is refused, and no paid analysis is sold or run for it.

## Flow 1: create an invoice with the payer analysis

MCP:

```json
{"name": "invoice_create", "arguments": {
  "chainId": "solana-mainnet", "recipient": "<RECEIVER>", "token": "USDC", "amount": "100",
  "memo": "October rent", "payerChecks": ["merkle-science"]}}
```

HTTP:

```bash
curl -sS https://swap.vurto.cc/v1/invoices -H 'content-type: application/json' --data '{
  "chainId": "solana-mainnet", "recipient": "<RECEIVER>", "token": "USDC", "amount": "100",
  "payerChecks": ["merkle-science"] }'
```

The answer carries `invoice.id` (`INV-XXXX-XXXX`), `invoice.url`, `invoice.payerChecks` and `invoice.analysis`
(`status`, `amount`, `to`), plus `next` with the call that pays it. The creator is the signed-in wallet, or the receiving wallet when there is no session. Tell the receiver the real number before creating it: "you ask 200 USDC, you receive 200, and
the analysis costs US$ 0.40, paid by you now". Then `invoice_analysis_pay` with `payer` = the creator and no `checks`, sign,
and `invoice_report_analysis_payment` with `txHash`. Share the link only after that: until then paying answers
`409 analysis_unpaid`.

Refusals: `403 receiver_blocked` (the receiving wallet failed the free screening; nothing is created),
`400 stablecoin_required`, `400 split_not_available_on_chain` (no configured EVM contract),
`503 analysis_tool_unavailable` (the tool is not answering; nothing is created or charged).

## Flow 2: pay an invoice (the payer analysis runs here)

1. Prove the paying wallet. MCP `destination_challenge` with `wallet` = payer, `receiver` = the
   invoice receiver (`invoice_get` shows it), `chainId` of the invoice; sign the `message` with the
   payer wallet; then `destination_authorize`. HTTP: `POST /v1/destination/challenge` and
   `POST /v1/destination/authorize`. Without it the next call answers
   `401 payer_signature_required` and nothing runs.
2. Build the payment. MCP `invoice_pay` `{"id": "INV-...", "payer": "<PAYER>"}`, HTTP
   `POST /v1/invoices/{id}/pay`. The free screening of both wallets runs, then the paid analysis the
   receiver chose, on the payer wallet. No field switches it off. Up to 2 payer wallets run here; after that the plan comes out with `warning`, and the analysis
   runs on the report of a confirmed payment of the whole amount. A rejected payer gets `403 payer_blocked` before paying, and `503 analysis_tool_unavailable` means try again
   in a few minutes. A transaction that reaches the receiver settles the invoice: the analysis refuses nothing after the money has arrived. The result goes to the creator alone, on the site, signed in with that wallet.
3. Approved, `method: "transfer"` delivers the whole amount to the receiver, with no fee in it. Sign it
   (`prepare_signing`), send it with `POST /v1/svm/execute` on Solana, and report the signature with
   `invoice_report_payment` (HTTP `POST /v1/invoices/{id}/payments`).
4. Paying with another token returns a swap plan. Follow the returned method; do not infer it from the token alone.

An invoice that carries `invoice.split` keeps it (only older ones do). For those, only a confirmed
transaction that, by itself, delivers the amount minus the fee to the receiver **and** the fee to the Vurto fee wallet,
taken from the payer, settles the invoice. Before signing one, check it yourself: exactly `split.receiverAmount` to the
receiver and `split.fee` to the fee wallet, which on Solana is `9KwgTV9sr4ydmiG4fCHN6PuNGPsF86BqLVcAh5i4nDHT` (an older
invoice can still name `FFiHFrFoa3knbcdxr4KVYekJmDRc28nfixmuZtgfmYyG`), nothing else. Refusals: `split_fee_missing`, `split_receiver_short`, `split_not_a_transfer`,
`split_not_from_payer`, and `403 analysis_offer_suspended` can apply. Do not try to save the fee: the money would reach
the receiver and the invoice would still be unpaid.

## Flow 3: the payer buys the receiver analysis

The analysis never goes inside the payment (`receiverChecks` with a tool answers `analysis_not_in_split`, on any invoice). Ask with the real
price, whatever the amount: "Do you want the receiving wallet to go through the
Merkle Science analysis before paying? It costs US$ 0.40, paid by you." Then:

MCP:

```json
{"name": "invoice_analysis_pay", "arguments": {"id": "INV-...", "payer": "<PAYER>", "checks": ["merkle-science"]}}
```

HTTP:

```bash
curl -sS https://swap.vurto.cc/v1/invoices/INV-7K3M-Q9XA/analysis-payment/transfer \
  -H 'content-type: application/json' --data '{"payer":"<PAYER>","checks":["merkle-science"]}'
```

A new purchase needs no wallet proof, the payment itself proves it; giving it up, changing the tools and
reusing a stored analysis do. The free screening of both wallets runs (`403 screening_blocked`). It returns
`receiverAnalysis` (`status: "awaiting_payment"`, `amount`, `to`) and one USDC transfer to the Vurto fee
wallet. **Sign that transaction exactly as returned**: it carries the mark that ties the payment to this
charge, and a transfer you build yourself is refused with `analysis_payment_rejected`, reason
`charge_not_tied`, after the money has left. If that happens do not pay again: prove the wallet
(`destination_challenge` with `receiver` = `details.feeWallet`, `chargeId` = the invoice id and `chargeTxHash` = that hash, then
`destination_authorize`) and report the same
hash. Sign and send it, then report it:

```json
{"name": "invoice_report_analysis_payment", "arguments": {"id": "INV-...", "payer": "<PAYER>", "txHash": "<SIGNATURE>"}}
```

HTTP: `POST /v1/invoices/{id}/analysis-payment` with `{"payer", "txHash"}`. The analysis runs right
away and `receiverAnalysis.result` comes back with the verdict and what each paid tool read.
`receiverAnalysis` never carries the receiving wallet. The `invoice` in the same answer shows it on
a common invoice, where it is public anyway, and hides it (`recipient: null`) on a confidential one.
An open, unpaid analysis does not hold `invoice_pay`, because anyone can open one naming a wallet: pay
and report it BEFORE `invoice_pay` if you want its verdict to count. A paid one goes stale when the
receiving wallet moves, and then `invoice_pay` answers `409 receiver_analysis_unpaid` until it is redone;
only `checks: []` gives it up. While one is open, the `invoice_pay` answer carries `warning`. A rejected receiver
makes `invoice_pay` answer `403 receiver_blocked`.

Sign the transfer as returned: it carries a mark that ties the transaction to this invoice and this payer, so another invoice to the same recipient cannot claim it (the report there ends as `tx_for_another_payment`). A transaction with no mark, a transfer you build yourself, a native transfer or a provider's ready-made route, still counts, but the first report the network confirms wins, so another invoice to the same recipient can take it. If a transaction of yours ends as `tx_for_another_payment`, prove the wallet that sent it (`POST /v1/destination/challenge` with `receiver` = the invoice recipient, `chargeId` = the invoice id and `chargeTxHash` = the hash, then `/authorize`) and report the same hash again.

Paying it from another token: `POST /v1/svm/swap` from the payer with `receiver` =
`receiverAnalysis.to` and `invoiceId` = the invoice. Only a transaction in which the fee wallet is
the only one that gains USDC counts.

## CLI

```bash
vurto-swap invoice create --chain solana --to <RECEIVER> --token USDC --amount 100 --payer-check merkle-science
vurto-swap invoice analysis-pay --id INV-XXXX-XXXX --wallet <CREATOR> --json | vurto-swap sign --wallet <CREATOR>
vurto-swap invoice pay --id INV-XXXX-XXXX --wallet <PAYER> --json | vurto-swap sign --wallet <PAYER>
vurto-swap invoice analysis-pay --id INV-XXXX-XXXX --wallet <PAYER> --check merkle-science --json | vurto-swap sign --wallet <PAYER>
vurto-swap invoice analysis-report --id INV-XXXX-XXXX --wallet <PAYER> --tx-hash <SIGNATURE>
```

## Rules for the agent

- Never sign anything the user did not ask for, and show the full amounts and the receiving wallet
  before signing.
- A Solana signature is not proof of payment: confirm with `swap_status` (or `GET /v1/svm/tx`) and
  read the invoice back with `invoice_get` before saying it is paid.
- Errors come as `{"error": {"code", "message", "details"}}`. Act on `code`, show `message`: on `/v1` and MCP
  it is in English and says what to do next. Repeating a report is safe; paying again is not.
- Batch payouts (many wallets, with or without a paid analysis of each): `payout_batch`, then `payout_charge`,
  then `payout_report_payment`. CLI: `vurto-swap payout --batch`, then `vurto-swap sign` on the file it saves.
- The older paid `checks` field on `invoice_create` is closed for new invoices (`400 paid_check_moved`): use `payerChecks`.
  An invoice created before keeps its charge, paid by the creator with `invoice_analysis_pay` (`payer` = the creator).
