_ registry / mcp http-sse · checked 2h ago

vurto-swap

https://swap.vurto.cc

Registry code: ef0c1f5355a47fa6

api record

Vurto Swap — token swaps at the best net price on 9 EVM chains (Ethereum, Optimism, BNB Chain, Gnosis, Polygon, Base, Arbitrum One, Avalanche, Unichain) across Velora, KyberSwap, 1inch, CoW Protocol and the direct pools Uniswap, SushiSwap, PancakeSwap, Aerodrome and QuickSwap, plus `composto`, a two-hop route that crosses two of those pools inside one transaction, and on Solana across Jupiter (router), Raydium, Orca and Meteora.

ONE set of tools, two networks: pick the engine with chainId — an integer for EVM, the string "solana-mainnet" for Solana. Everything else is the same vocabulary.…

endpoint
https://swap.vurto.cc/mcp
protocol
http-sse ·2025-03-26
authentication
none observed
public key
none — nobody has proven they own this listing · is it yours? claim it
karma
0 · newcomer
_ is it live, free and safe measured by this hub
Is vurto-swap live?
Yes — it answered the hub's last check (checked 2h ago). It answered 99% of checks over the last 30 days.
Is vurto-swap free to use?
Yes — the hub reached it with no key and no payment.
What tools does vurto-swap have?
22 tools: payout_charge, double_build, nn_quote, nn_build, invoice_report_payment, double_quote, report_execution, payout_report_payment, ….
Is vurto-swap safe to connect?
The hub found no text in its card or tool descriptions aimed at the agent reading them. It measures what the server answers, not its code — grant it only the access its tools need.
reachable
live
uptime, 30 days
98.8%

90 days 98.8%· all time 98.8%

latency
528ms

last good check

priced tools
0

of 22 tools

_ answered our checks, 90 days 331 checks · signed record
  • degraded → live
  • live → degraded· timeout after 20000ms
  • degraded → live
  • live → degraded· timeout after 20000ms
  • degraded → live
_ what it is for
used for
  • get the best swap route across dexes
  • build a swap transaction
  • create a crypto payment invoice
  • check swap status
takes → gives
text, data → data, payments
tools
6 reads3 changes data4 moves money
_ usage and payments 30 days

Calls placed through this hub's router, from its own receipts. Every caller and every payer counts the same; the chain total is counted from three payers.

accounts
0

through this hub

calls served
0

successful

paid through this hub
0 USDC

what callers paid

inferred, not observed

Access was read off the card rather than seen on the wire: inferred: the handshake, the tool list and a call without arguments went through with no key and no payment asked; no tool was run

_ what it can do 22 tools
22 never probed 0 of 22 classified

Price is per tool, not per server. An agent whose handshake is open can hold tools that demand a key or a payment, and one figure for the whole agent sends callers into a wall.

  • payout_charge unknown never probed

    Step 2 of a payout_batch with checks, on Solana or EVM. After signing and sending payout_batch's charge.transaction, hand its signature or hash here with the loteId and payer. The server verifies the charge on-chain, runs the paid analysis on EVERY destination, EXCLUDES any wallet that is blocked or over the payer's risk threshold (it receives nothing, its money never moved), and returns { transactions[], evm?, approved[] (each with its scan result), rejected[] (wallet, reason) }. On Solana, sign each transactions[i].transaction (prepare_signing, POST to /v1/svm/execute) and call payout_report_payment with that signature and its invoiceIds. On EVM, sign evm.steps IN ORDER (approve, then pay the IBBs contract) and call payout_report_payment with the pay transaction hash and evm.invoiceIds. Idempotent with the same charge signature (re-returns the built batch, without the wallets already paid, listed in alreadyPaid). The charge hash goes only here, never to payout_report_payment. Errors: batch_charge_not_found, invalid_tx_hash, analysis_payment_pending (409, the network has not confirmed the charge yet, send the signature again shortly), analysis_payment_rejected (the transaction does not pay this charge; details.reason charge_not_tied when it is not the transaction payout_batch built: do not pay again, prove the wallet with destination_challenge (receiver = details.feeWallet, chargeId = the loteId, chargeTxHash = that hash), then destination_authorize, and call this again), tx_already_used.

    mcp-tool

    {
      "type": "object",
      "required": [
        "loteId",
        "payer"
      ],
      "properties": {
        "payer": {
          "type": "string",
          "description": "The wallet that paid the charge (base58 on Solana, 0x on EVM)."
        },
        "loteId": {
          "type": "string",
          "description": "The loteId from payout_batch's charge."
        },
        "txHash": {
          "type": "string",
          "description": "The Solana signature or EVM transaction hash of the charge payment. Omit only to rebuild a fully-reused batch (website session only)."
        }
      },
      "additionalProperties": false
    }
    arguments 22 lines
  • double_build moves money unknown never probed

    Builds signable/sendable plans for BOTH legs of a Double Out or Double In swap — two ordinary swap_build calls under the hood, kept together for convenience. Returns { legA, legB }, each a full SwapPlan exactly like swap_build's. The two legs are NOT atomic — there is no combined contract call, each is a transaction (or CoW signature) the wallet sends separately, same as any other swap. Execute leg A fully first (steps, signing, report_execution) and confirm it landed before starting leg B. If leg A fails or is rejected, do NOT execute leg B — proceeding would leave the wallet with only half the ratio the user asked for, which defeats the purpose of a Double swap.

    mcp-tool

    {
      "type": "object",
      "required": [
        "chainId",
        "wallet",
        "legA",
        "legB"
      ],
      "properties": {
        "legA": {
          "type": "object",
          "properties": {
            "amount": {
              "type": "string",
              "description": "Human decimal amount, e.g. \"100\". Use this OR amountRaw, not both."
            },
            "wallet": {
              "type": "string",
              "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
            },
            "chainId": {
              "type": [
                "integer",
                "string"
              ],
              "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
            },
            "quoteId": {
              "type": "string",
              "description": "Optional: build exactly this route from a prior double_quote."
            },
            "tokenIn": {
              "type": "string",
              "description": "Contract address (Solana: mint), or symbol (case-insensitive). A symbol matching more than one token on this chain fails with ambiguous_token and every candidate — pick the address you meant and retry. On Solana only VERIFIED tokens resolve by symbol, because there anyone can mint a token using another one's symbol; an unverified token has to be named by its mint."
            },
            "receiver": {
              "type": "string",
              "description": "Optional: deliver the output to this address instead of the signing wallet. Only providers with supportsReceiver true on the resulting quote honor it — others are left out of quotes[] entirely rather than risk sending to the wrong address. supportsReceiver is present on Solana quotes too, so read it instead of assuming. On Solana, selling into native SOL with a separate destination is refused on every provider (receiver_native_sol_unsupported): closing the wrapped-SOL account sends balance and rent to whoever signs. Ask for wSOL instead. Building with a receiver needs the paying wallet's signed authorization first (destination_challenge, then destination_authorize), or the build fails with destination_not_authorized."
            },
            "tokenOut": {
              "type": "string",
              "description": "Contract address, or symbol."
            },
            "amountRaw": {
              "type": "string",
              "description": "Raw integer string in tokenIn's smallest unit."
            },
            "slippageBps": {
              "type": "integer",
              "description": "Optional, a sane per-pair default applies when omitted."
            }
          },
          "additionalProperties": false
        },
        "legB": {
          "type": "object",
          "properties": {
            "amount": {
              "type": "string",
              "description": "Human decimal amount, e.g. \"100\". Use this OR amountRaw, not both."
            },
            "wallet": {
              "type": "string",
              "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
            },
            "chainId": {
              "type": [
                "integer",
                "string"
              ],
              "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
            },
            "quoteId": {
              "type": "string"
            },
            "tokenIn": {
              "type": "string",
              "description": "Contract address (Solana: mint), or symbol (case-insensitive). A symbol matching more than one token on this chain fails with ambiguous_token and every candidate — pick the address you meant and retry. On Solana only VERIFIED tokens resolve by symbol, because there anyone can mint a token using another one's symbol; an unverified token has to be named by its mint."
            },
            "receiver": {
              "type": "string",
              "description": "Optional: deliver the output to this address instead of the signing wallet. Only providers with supportsReceiver true on the resulting quote honor it — others are left out of quotes[] entirely rather than risk sending to the wrong address. supportsReceiver is present on Solana quotes too, so read it instead of assuming. On Solana, selling into native SOL with a separate destination is refused on every provider (receiver_native_sol_unsupported): closing the wrapped-SOL account sends balance and rent to whoever signs. Ask for wSOL instead. Building with a receiver needs the paying wallet's signed authorization first (destination_challenge, then destination_authorize), or the build fails with destination_not_authorized."
            },
            "tokenOut": {
              "type": "string",
              "description": "Contract address, or symbol."
            },
            "amountRaw": {
              "type": "string",
              "description": "Raw integer string in tokenIn's smallest unit."
            },
            "slippageBps": {
              "type": "integer",
              "description": "Optional, a sane per-pair default applies when omitted."
            }
          },
          "additionalProperties": false
        },
        "wallet": {
          "type": "string",
          "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
        },
        "maxSlippageBps": {
          "type": "integer",
          "description": "Optional ceiling, 0-10000, applied to both legs."
        }
      },
      "additionalProperties": false
    }
    arguments 116 lines
  • nn_quote reads unknown 10h ago

    N:N — quotes a basket where N input tokens fund M output tokens in ONE atomic on-chain transaction. The backend runs a waterfall allocation deciding which input finances which output, then quotes the real tokenIn->tokenOut route for each resulting slice through the same provider fan-out swap_quote uses. NOT decomposable into independent swap_quote/double_quote calls — the allocation itself is the thing being computed, not just N+M separate prices for legs you already know. inputLegs[]: what you sell (tokenIn + amount or amountRaw, each). outputLegs[]: what you want back, as outputPercent — an integer percent of the TOTAL basket value, not a fixed amount, because the actual split depends on the allocation; every outputLegs[].outputPercent in the request must sum to exactly 100. Up to 10 combined input+output legs; the waterfall never produces more than inputLegs.length + outputLegs.length - 1 real on-chain legs. Returns { legs[], failures[] }. Each entry in legs[] is a real quoted tokenIn->tokenOut leg (a NormalizedQuote under .quote, plus amountIn/tokenIn/tokenOut/receiver for that slice) — this is what nn_build will execute, not a rough preview. failures[] lists any slice that found no route; a partial basket is possible and reported, never silently dropped.

    mcp-tool

    {
      "type": "object",
      "required": [
        "chainId",
        "inputLegs",
        "outputLegs"
      ],
      "properties": {
        "wallet": {
          "type": "string",
          "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\"). On EVM the multi-swap router must be deployed on the chain or the quote fails with multi_swap_not_supported_on_chain; on Solana there is no router contract, several top-level instructions in one transaction are already all-or-nothing by runtime rule."
        },
        "inputLegs": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "tokenIn"
            ],
            "properties": {
              "amount": {
                "type": "string",
                "description": "Human decimal amount, e.g. \"100\". Use this OR amountRaw, not both."
              },
              "tokenIn": {
                "type": "string",
                "description": "Contract address, or symbol (case-insensitive)."
              },
              "amountRaw": {
                "type": "string",
                "description": "Raw integer string in tokenIn's smallest unit."
              }
            },
            "additionalProperties": false
          },
          "minItems": 1
        },
        "outputLegs": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "tokenOut",
              "outputPercent"
            ],
            "properties": {
              "receiver": {
                "type": "string",
                "description": "Optional: deliver this leg's output to a different address than the signing wallet."
              },
              "tokenOut": {
                "type": "string",
                "description": "Contract address, or symbol."
              },
              "outputPercent": {
                "type": "integer",
                "description": "Integer percent (1-100) of the TOTAL basket value this leg receives. Every outputLegs[].outputPercent in the request must sum to exactly 100."
              }
            },
            "additionalProperties": false
          },
          "minItems": 1
        },
        "slippageBps": {
          "type": "integer",
          "description": "Optional, 5-500, applied to every leg. Default 50."
        }
      },
      "additionalProperties": false
    }
    arguments 77 lines
  • nn_build moves money unknown never probed

    Builds ONE signable/sendable atomic transaction executing every leg of an N:N basket through VurtoSwapRouter. Always re-quotes the whole basket fresh from chainId/inputLegs/outputLegs — there is no quoteId handoff for N:N, pass the same fields used for nn_quote (or skip nn_quote and call this directly). No API key required: pass the wallet that will sign. A machine credential is optional and only raises your limit from the per-IP cap to the credential budget. Returns steps[]: one approve step per DISTINCT input token that still needs allowance, followed by ONE transaction step that executes every leg atomically. The approve target is the VurtoSwapRouter address (steps[].spender / the build's router), NOT each leg's underlying provider — this router pulls every input token itself inside one contract call, so approving providers individually the way swap_build does would approve the wrong address. If simulation.status is approval_required, send the approve step(s) first and call nn_build again for the executable transaction. legs[].routeSwitch, when present on a leg, means the provider the quote picked for THAT leg refused to build (it hit its request limit) and the leg was built with another provider instead: {from, to, reason}. Only that leg changed, the others are untouched, and the replacement is what will be signed: say which provider replaced it before the user signs. IMPORTANT: report_execution and swap_status do NOT support nn_build's transaction step — both key off a single quoteId, and this build has none (it is one transaction covering every leg, not one quote). After sending it, confirm success by checking the transaction receipt directly, not swap_status.

    mcp-tool

    {
      "type": "object",
      "required": [
        "chainId",
        "wallet",
        "inputLegs",
        "outputLegs"
      ],
      "properties": {
        "wallet": {
          "type": "string",
          "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
        },
        "inputLegs": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "tokenIn"
            ],
            "properties": {
              "amount": {
                "type": "string",
                "description": "Human decimal amount, e.g. \"100\". Use this OR amountRaw, not both."
              },
              "tokenIn": {
                "type": "string",
                "description": "Contract address, or symbol (case-insensitive)."
              },
              "amountRaw": {
                "type": "string",
                "description": "Raw integer string in tokenIn's smallest unit."
              }
            },
            "additionalProperties": false
          },
          "minItems": 1
        },
        "outputLegs": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "tokenOut",
              "outputPercent"
            ],
            "properties": {
              "receiver": {
                "type": "string",
                "description": "Optional: deliver this leg's output to a different address than the signing wallet."
              },
              "tokenOut": {
                "type": "string",
                "description": "Contract address, or symbol."
              },
              "outputPercent": {
                "type": "integer",
                "description": "Integer percent (1-100) of the TOTAL basket value this leg receives. Every outputLegs[].outputPercent in the request must sum to exactly 100."
              }
            },
            "additionalProperties": false
          },
          "minItems": 1
        },
        "slippageBps": {
          "type": "integer",
          "description": "Optional, 5-500, applied to every leg. Default 50."
        }
      },
      "additionalProperties": false
    }
    arguments 78 lines
  • invoice_report_payment changes data unknown never probed

    Hand the payment transaction to the server, right after sending it. The server reads the transaction on-chain and measures what reached the receiver in the invoice token; the payer must be the signer and the transaction must be newer than the invoice. The payer is screened again here (payer_blocked: a sanctioned or issuer-frozen payer does not count as paid, and once the network confirms the transaction the refusal is kept in the 10-year analysis record). With a paid analysis on the invoice and no prior proof of the payer wallet, the transaction itself is the proof: until the network confirms it the call returns payment_pending (409) and records nothing, so call again once it is mined. Pending until mined; invoice_get re-checks. An invoice holds at most 5 pending and 30 unconfirmed payments; past that, too_many_pending (429) until the network confirms the transaction, and a confirmed one is always accepted, so call again once it is mined. A hash pays each receiver once (tx_already_used once it confirmed another invoice of the same receiver and token); different receivers in one transaction are a batch payout.

    mcp-tool

    {
      "type": "object",
      "required": [
        "id",
        "payer",
        "txHash"
      ],
      "properties": {
        "id": {
          "type": "string",
          "description": "INV-XXXX-XXXX or the 8-character id."
        },
        "payer": {
          "type": "string",
          "description": "The wallet that signed the payment."
        },
        "method": {
          "enum": [
            "transfer",
            "swap"
          ],
          "type": "string",
          "description": "From invoice_pay.method."
        },
        "txHash": {
          "type": "string",
          "description": "EVM transaction hash, or the Solana signature."
        }
      },
      "additionalProperties": false
    }
    arguments 31 lines
  • double_quote reads unknown 15h ago

    Compares ranked routes for TWO swap legs at once — "Double Out" (one source token split into two destinations) or "Double In" (two source tokens converging on one destination). This exists because building a liquidity pool or matching a target ratio needs both legs priced against the market at the same instant, not one after another with the price moving in between. Each leg is independently quoted (two ordinary swap_quote calls under the hood) — this tool is a convenience that keeps them together, not a combined/atomic route. For mode "out": legA.tokenIn must equal legB.tokenIn (the shared source); tokenOut differs. For mode "in": legA.tokenOut must equal legB.tokenOut (the shared destination); tokenIn differs. Pass the exact amount each leg should trade — this tool does not compute percentages or splits for you. If the shared token is the chain's native asset, remember gas is paid twice (once per leg's eventual transaction) — do not quote/build a total that leaves nothing for the second leg's gas.

    mcp-tool

    {
      "type": "object",
      "required": [
        "mode",
        "chainId",
        "legA",
        "legB"
      ],
      "properties": {
        "legA": {
          "type": "object",
          "required": [
            "tokenIn",
            "tokenOut"
          ],
          "properties": {
            "amount": {
              "type": "string",
              "description": "Human decimal amount, e.g. \"100\". Use this OR amountRaw, not both."
            },
            "wallet": {
              "type": "string",
              "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
            },
            "chainId": {
              "type": [
                "integer",
                "string"
              ],
              "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
            },
            "tokenIn": {
              "type": "string",
              "description": "Contract address (Solana: mint), or symbol (case-insensitive). A symbol matching more than one token on this chain fails with ambiguous_token and every candidate — pick the address you meant and retry. On Solana only VERIFIED tokens resolve by symbol, because there anyone can mint a token using another one's symbol; an unverified token has to be named by its mint."
            },
            "receiver": {
              "type": "string",
              "description": "Optional: deliver the output to this address instead of the signing wallet. Only providers with supportsReceiver true on the resulting quote honor it — others are left out of quotes[] entirely rather than risk sending to the wrong address. supportsReceiver is present on Solana quotes too, so read it instead of assuming. On Solana, selling into native SOL with a separate destination is refused on every provider (receiver_native_sol_unsupported): closing the wrapped-SOL account sends balance and rent to whoever signs. Ask for wSOL instead. Building with a receiver needs the paying wallet's signed authorization first (destination_challenge, then destination_authorize), or the build fails with destination_not_authorized."
            },
            "tokenOut": {
              "type": "string",
              "description": "Contract address, or symbol."
            },
            "amountRaw": {
              "type": "string",
              "description": "Raw integer string in tokenIn's smallest unit."
            },
            "slippageBps": {
              "type": "integer",
              "description": "Optional, a sane per-pair default applies when omitted."
            }
          },
          "additionalProperties": false
        },
        "legB": {
          "type": "object",
          "required": [
            "tokenIn",
            "tokenOut"
          ],
          "properties": {
            "amount": {
              "type": "string",
              "description": "Human decimal amount, e.g. \"100\". Use this OR amountRaw, not both."
            },
            "wallet": {
              "type": "string",
              "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
            },
            "chainId": {
              "type": [
                "integer",
                "string"
              ],
              "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
            },
            "tokenIn": {
              "type": "string",
              "description": "Contract address (Solana: mint), or symbol (case-insensitive). A symbol matching more than one token on this chain fails with ambiguous_token and every candidate — pick the address you meant and retry. On Solana only VERIFIED tokens resolve by symbol, because there anyone can mint a token using another one's symbol; an unverified token has to be named by its mint."
            },
            "receiver": {
              "type": "string",
              "description": "Optional: deliver the output to this address instead of the signing wallet. Only providers with supportsReceiver true on the resulting quote honor it — others are left out of quotes[] entirely rather than risk sending to the wrong address. supportsReceiver is present on Solana quotes too, so read it instead of assuming. On Solana, selling into native SOL with a separate destination is refused on every provider (receiver_native_sol_unsupported): closing the wrapped-SOL account sends balance and rent to whoever signs. Ask for wSOL instead. Building with a receiver needs the paying wallet's signed authorization first (destination_challenge, then destination_authorize), or the build fails with destination_not_authorized."
            },
            "tokenOut": {
              "type": "string",
              "description": "Contract address, or symbol."
            },
            "amountRaw": {
              "type": "string",
              "description": "Raw integer string in tokenIn's smallest unit."
            },
            "slippageBps": {
              "type": "integer",
              "description": "Optional, a sane per-pair default applies when omitted."
            }
          },
          "additionalProperties": false
        },
        "mode": {
          "enum": [
            "out",
            "in"
          ],
          "type": "string",
          "description": "\"out\": one source, two destinations. \"in\": two sources, one destination."
        },
        "wallet": {
          "type": "string",
          "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
        }
      },
      "additionalProperties": false
    }
    arguments 121 lines
  • report_execution changes data unknown never probed

    Reports a completed swap, closing the loop. EVM transaction: pass wallet + txHash + quoteId; never report an approve step as an execution. EVM CoW signature: pass wallet + chainId + quoteId + signature; the server reloads the stored build and submits the signed order, returning uid (there is no transaction hash for this path). Solana: pass buildId + signature; the server verifies the fee payer and transaction on the network. No API key required; a machine credential only raises limits.

    mcp-tool

    {
      "type": "object",
      "properties": {
        "txHash": {
          "type": "string",
          "pattern": "^0x[0-9a-fA-F]{64}$",
          "description": "EVM transaction swap only; do not report approve hashes."
        },
        "wallet": {
          "type": "string",
          "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
        },
        "buildId": {
          "type": "string",
          "description": "Solana: buildId returned by swap_build."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM CoW: integer chain id. Solana may use \"solana-mainnet\", but buildId + signature are sufficient."
        },
        "quoteId": {
          "type": "string",
          "description": "EVM: quote id from the built plan."
        },
        "signature": {
          "type": "string",
          "description": "EVM: EIP-712 CoW signature. Solana: transaction signature."
        }
      },
      "additionalProperties": false
    }
    arguments 34 lines
  • payout_report_payment unknown never probed

    Hand one batch transaction to the server, right after sending it, with the invoiceIds that payout_batch listed for it. Each invoice is verified on-chain like any invoice payment (what reached that receiver); call again a few seconds later if some are still pending.

    mcp-tool

    {
      "type": "object",
      "required": [
        "txHash",
        "payer",
        "invoiceIds"
      ],
      "properties": {
        "payer": {
          "type": "string",
          "description": "The wallet that signed."
        },
        "txHash": {
          "type": "string",
          "description": "The Solana signature or EVM transaction hash."
        },
        "invoiceIds": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "maxItems": 50,
          "minItems": 1,
          "description": "EVM: payout_batch evm.invoiceIds (all of them, paid by the one pay transaction). Solana: payout_batch.transactions[i].invoiceIds."
        }
      },
      "additionalProperties": false
    }
    arguments 28 lines
  • invoice_analysis_pay unknown never probed

    Do not use it on an invoice whose split.rule is "brackets" (created since 10/11/2026): its fee is inside the payment and already pays the analysis of both wallets, and the call is refused with analysis_included_in_fee (409). Without checks: the charge of the invoice creator, for an older invoice with payerChecks or paid checks whose analysis.status is awaiting_payment (see invoice_get). Builds ONE USDC transfer of analysis.amount (0.10 Scorechain, 0.40 Merkle Science, 0.50 both) to the Vurto fee wallet (analysis.to), signed by the invoice creator. Sign the charge transaction exactly as returned: it carries the mark that ties the payment to this charge (16 bytes after the transfer arguments on EVM, a memo on Solana). A transfer you build yourself is refused with analysis_payment_rejected, reason charge_not_tied, after the money has left; do not pay again, prove the wallet (destination_challenge with wallet = payer, receiver = details.feeWallet, chargeId = this charge and chargeTxHash = that hash, then destination_authorize) and report the same hash again. Nothing is signed or sent here. The free screening runs first on the receiving wallet and on the creator: a rejected wallet gets screening_blocked (403) and nothing is built; a screening that cannot be read gets screening_unavailable (503). payer must be the creator (the receiving wallet when the invoice was created without a session, which is always the case over MCP); any other wallet gets not_invoice_creator (403) before anything is built. plan has the same shape as invoice_pay (prepare_signing; on Solana POST the signed transaction to /v1/svm/execute), then call invoice_report_analysis_payment with the hash or signature. Paying it from another token is a swap built over the HTTP API (POST /v1/swap on EVM, POST /v1/svm/swap on Solana) from the creator wallet with tokenOut = analysis.token, receiver = analysis.to and invoiceId = this invoice, sized so the guaranteed minimum covers analysis.amountRaw; report its hash or signature to invoice_report_analysis_payment. On EVM only a swap built that way counts (the transaction must match that build); on Solana the Vurto fee wallet must be the only wallet whose USDC rises in it, and it must be the transaction we built, which carries the mark. The minimum must stay between the charge and 10% above it (charge_swap_below_amount, charge_swap_above_amount). A swap that only pays a fee to the same wallet does not count. Errors: no_paid_check, analysis_already_paid, analysis_included_in_fee, invoice_already_paid, not_invoice_creator, screening_blocked, screening_unavailable. Invoices of the new model (Solana, and EVM networks with a split contract): this is how the PAYER buys the paid analysis of the RECEIVING wallet, with their own money, before paying. Pass payer = the paying wallet and checks (["merkle-science"] 0.40, ["scorechain"] 0.10, both 0.50 USDC, the price of ONE wallet). A new purchase needs no wallet proof, the payment itself proves it; giving it up, changing the tools of an existing charge and reusing a stored analysis do (destination_challenge/destination_authorize for this invoice's receiver; without it payer_signature_required, 401). The free screening of both wallets must pass (screening_blocked 403). It returns receiverAnalysis {status: awaiting_payment, amount, to} and the USDC transfer to sign; report it with invoice_report_analysis_payment (txHash and payer). The price is the same whatever the amount, and the analysis never goes inside the payment. analysis_tool_unavailable (503) when the tool is not answering: nothing is charged. 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 refuses with receiver_analysis_unpaid (409) until it is redone. checks: [] gives it up. The result comes back without the receiving wallet. Paying it from another token exists on Solana only: POST /v1/svm/swap from the payer with receiver = the fee wallet (receiverAnalysis.to) and invoiceId = this invoice. On EVM the payer pays with the USDC transfer.

    mcp-tool

    {
      "type": "object",
      "required": [
        "id",
        "payer"
      ],
      "properties": {
        "id": {
          "type": "string",
          "description": "INV-XXXX-XXXX or the 8-character id."
        },
        "payer": {
          "type": "string",
          "description": "With checks: the paying wallet, which buys the analysis of the receiving wallet. Without checks: the invoice creator wallet, which pays the analysis it asked for (payerChecks, or the older paid checks of an invoice created before 07/11/2026)."
        },
        "checks": {
          "type": "array",
          "items": {
            "enum": [
              "scorechain",
              "merkle-science"
            ],
            "type": "string"
          },
          "description": "The paid analyses of the RECEIVING wallet the payer buys. [] gives up an unpaid one, and only [] does: on an invoice whose payer analysis is split, leaving it out is invalid_check (400)."
        }
      },
      "additionalProperties": false
    }
    arguments 29 lines
  • invoice_pay moves money unknown never probed

    Build the plan to pay an invoice from payer, with the token payer holds (default: the invoice token). Nothing is signed or sent here. Both wallets are screened first (payer_blocked, receiver_blocked); when the invoice has checks ["scorechain"] (see invoice_get), the creator chose and paid the Scorechain sanctions API, so this call sends the payer wallet and the receiver wallet to Scorechain, a third party (an invoice created before 22/10/2026 with the then-free Scorechain keeps running it without a charge). method "transfer": same token, a direct transfer built from the stored invoice (no fee, no gain; the receiver sees the payer as sender). method "swap": another token; amountIn is computed so the GUARANTEED minimum output covers the requested amount, the route is always the one with GAIN when there is one, and the output goes straight to the receiver (the transaction is public and signed by the payer, so the receiver can see the paying wallet on-chain). Any surplus over the requested amount goes to the receiver. plan has the same shape as a swap_build plan: on EVM sign steps[] in order with prepare_signing (approve steps first, then the transaction); on Solana pass {transaction, executionRef} to prepare_signing and POST the signed transaction to /v1/svm/execute. If simulation.status is approval_required, send the approve and call invoice_pay again. When the invoice has paid checks, the creator must have paid the analysis first (analysis_unpaid, 409). With "merkle-science" this call then sends the payer wallet and the receiver wallet to Didit/Merkle Science, and a HIGH or CRITICAL risk (score 70 or more) refuses with payer_blocked or receiver_blocked; the detail shows in invoice_get analysis.report. At most 3 different payer wallets are analysed per invoice by each paid check; a 4th gets analysis_attempts_exceeded (429). Since 23/10/2026 the payer proves the wallet BEFORE the paid analysis runs on it: over MCP that proof is the destination authorization signed by the payer for this invoice's receiver (destination_challenge with wallet = payer, receiver = the invoice receiver, chainId of the invoice, sign the message, then destination_authorize). Without it this call returns payer_signature_required (401) and no analysis slot is spent. Invoices with payerChecks and split.rule "brackets" (since 10/11/2026): nothing is paid first; the paid analysis runs HERE on BOTH wallets, the payer and the receiver, after the free screening, and the plan is the split that delivers split.receiverAmount to the receiver and split.fee to the Vurto fee wallet. Older invoices with payerChecks: the creator pays the analysis first (analysis_unpaid, 409), and it runs HERE, on the payer wallet, after its free screening passes; no field switches it off. The payer proves the wallet first (destination_challenge/destination_authorize; payer_signature_required 401). Up to 2 different 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, with the result going to the creator. A transaction that reaches the receiver settles the invoice: the analysis refuses nothing after the money has arrived. analysis_tool_unavailable (503) means try again in a few minutes. The plan delivers the whole amount to the receiver. An invoice that carries split keeps it (see invoice_get split): method "transfer" is then ONE payment transaction (on EVM, sign the exact approve step first, then VurtoInvoiceSplit.pay) with split.receiverAmount to the receiver and split.fee to the Vurto fee wallet, and only that transaction settles it; analysis_offer_suspended (403) applies only to those. With another token, method "swap_then_transfer": plan is a swap into the PAYER's own wallet and next is this same call again, to build the split; on Solana method "swap" does both in one transaction. A receiver analysis (invoice_analysis_pay) only counts here if it was paid and reported first: open and unpaid, it does not hold this call, and the answer carries warning and receiverAnalysis. Paid and stale gets receiver_analysis_unpaid (409), and a rejected receiver gets receiver_blocked. With method "swap", pass invoiceId to prepare_signing so it points to the invoice report. Sign the transaction as returned: it is tied to this invoice and payer, so another invoice to the same recipient cannot claim it (tx_for_another_payment). A transfer built by hand, a native transfer and a ready-made route of a provider are not, and the first report the network confirms wins. If a transaction of yours ends as tx_for_another_payment, prove the wallet (destination_challenge with chargeId = the invoice id and chargeTxHash = the hash, then destination_authorize) and report it again. Then call invoice_report_payment with the hash (EVM) or signature (Solana). Errors: price_moved (the minimum fell below the request between quote and build — call again), no_route, native_sol_only (an invoice in SOL can only be paid in SOL), invoice_already_paid, private_invoice_paused (a private invoice created before 14/10/2026, paused until the Vurto Private Contract exists). Both wallets are screened before the plan is built: the paying one (payer_blocked) and the receiving one (receiver_blocked). screening_unavailable (503) means the screening could not finish, try again in a few seconds.

    mcp-tool

    {
      "type": "object",
      "required": [
        "id",
        "payer"
      ],
      "properties": {
        "id": {
          "type": "string",
          "description": "INV-XXXX-XXXX or the 8-character id."
        },
        "payer": {
          "type": "string",
          "description": "The wallet that will sign and pay, on the invoice network."
        },
        "tokenIn": {
          "type": "string",
          "description": "Optional: address/mint or symbol of the token the payer pays with. Omit to pay in the invoice token."
        },
        "slippageBps": {
          "type": "integer",
          "description": "Optional, default 50. The guaranteed minimum is computed after it, so a tighter slippage asks the payer for less."
        }
      },
      "additionalProperties": false
    }
    arguments 26 lines
  • swap_quote reads unknown 10h ago

    Compare ranked routes across providers for a swap, without building or spending anything. Ranked by net value after gas and platform fee, not raw output, with ONE unit price for the output token across every route, so a friendlier price feed can never put a route that delivers fewer tokens on top. Each quote also carries estimatedGas, the gas in units behind the same gasUsd, if you would rather rank against a gas price you read yourself. A quote is only usable by swap_build for about 10-12 seconds — do not hold onto a quoteId and build it later, quote again instead.

    mcp-tool

    {
      "type": "object",
      "required": [
        "chainId",
        "tokenIn",
        "tokenOut"
      ],
      "properties": {
        "amount": {
          "type": "string",
          "description": "Human decimal amount, e.g. \"100\". Use this OR amountRaw, not both."
        },
        "wallet": {
          "type": "string",
          "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
        },
        "tokenIn": {
          "type": "string",
          "description": "Contract address (Solana: mint), or symbol (case-insensitive). A symbol matching more than one token on this chain fails with ambiguous_token and every candidate — pick the address you meant and retry. On Solana only VERIFIED tokens resolve by symbol, because there anyone can mint a token using another one's symbol; an unverified token has to be named by its mint."
        },
        "receiver": {
          "type": "string",
          "description": "Optional: deliver the output to this address instead of the signing wallet. Only providers with supportsReceiver true on the resulting quote honor it — others are left out of quotes[] entirely rather than risk sending to the wrong address. supportsReceiver is present on Solana quotes too, so read it instead of assuming. On Solana, selling into native SOL with a separate destination is refused on every provider (receiver_native_sol_unsupported): closing the wrapped-SOL account sends balance and rent to whoever signs. Ask for wSOL instead. Building with a receiver needs the paying wallet's signed authorization first (destination_challenge, then destination_authorize), or the build fails with destination_not_authorized."
        },
        "tokenOut": {
          "type": "string",
          "description": "Contract address, or symbol."
        },
        "amountRaw": {
          "type": "string",
          "description": "Raw integer string in tokenIn's smallest unit."
        },
        "slippageBps": {
          "type": "integer",
          "description": "Optional, a sane per-pair default applies when omitted."
        }
      },
      "additionalProperties": false
    }
    arguments 46 lines
  • swap_build moves money unknown never probed

    Build a signable/sendable plan for a swap. This is the tool that does the work — an agent that only knows this tool can execute a swap end to end. Quotes and builds the best route in one call when quoteId is omitted (recommended): a route with GAIN first, re-quoting up to 3 rounds total before accepting one without gain, the same rule as Invoice; pass quoteId from a prior swap_quote to build exactly that route instead. No API key required: pass the wallet that will sign. A machine credential is optional and only raises your limit from the per-IP cap to the credential budget. Four things to hold onto: 1. steps[] are ORDERED and REQUIRED. Skipping an approve step guarantees a revert. 2. If simulation.status is "approval_required", sign/send only the approve step(s), do not report them as the swap execution, then call swap_build again with quoteId set to the quote.id of that build (the approved route; without it a fresh quote may pick another provider whose spender you never approved). If it is "incomplete", do not sign anything: the transaction was never independently verified. 3. If a step has type "signature", there is no transaction and never will be one for that step — what exists afterward is the uid from report_execution, not a hash. 4. If the provider is cowswap and the token sold is the chain's native asset, the transaction only REGISTERS the order — a successful receipt is not a successful swap. Use swap_status, not the receipt, to know what actually happened. 5. routeSwitch, when present, means the route you asked for refused to build (it hit its request limit) and the plan was built with another provider instead: {from, to, reason}. The quote in the plan is the route that will actually be signed. If the user picked that route themselves, say which provider replaced it before they sign.

    mcp-tool

    {
      "type": "object",
      "required": [
        "chainId",
        "wallet"
      ],
      "properties": {
        "amount": {
          "type": "string",
          "description": "Human decimal amount, e.g. \"100\". Use this OR amountRaw, not both."
        },
        "loteId": {
          "type": "string",
          "description": "Paying a batch charge with another token: the loteId from payout_batch, with tokenOut = charge.token and receiver = charge.feeWallet. The guaranteed minimum must stay between the charge and 10% above it."
        },
        "wallet": {
          "type": "string",
          "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
        },
        "quoteId": {
          "type": "string",
          "description": "Optional: build exactly this route from a prior swap_quote, instead of quoting fresh."
        },
        "tokenIn": {
          "type": "string",
          "description": "Contract address (Solana: mint), or symbol (case-insensitive). A symbol matching more than one token on this chain fails with ambiguous_token and every candidate — pick the address you meant and retry. On Solana only VERIFIED tokens resolve by symbol, because there anyone can mint a token using another one's symbol; an unverified token has to be named by its mint."
        },
        "receiver": {
          "type": "string",
          "description": "Optional: deliver the output to this address instead of the signing wallet. Only providers with supportsReceiver true on the resulting quote honor it — others are left out of quotes[] entirely rather than risk sending to the wrong address. supportsReceiver is present on Solana quotes too, so read it instead of assuming. On Solana, selling into native SOL with a separate destination is refused on every provider (receiver_native_sol_unsupported): closing the wrapped-SOL account sends balance and rent to whoever signs. Ask for wSOL instead. Building with a receiver needs the paying wallet's signed authorization first (destination_challenge, then destination_authorize), or the build fails with destination_not_authorized."
        },
        "tokenOut": {
          "type": "string",
          "description": "Contract address, or symbol."
        },
        "amountRaw": {
          "type": "string",
          "description": "Raw integer string in tokenIn's smallest unit."
        },
        "invoiceId": {
          "type": "string",
          "description": "Paying an analysis charge with another token: the invoice id, with receiver = the fee wallet of that charge. Same rule for the minimum."
        },
        "slippageBps": {
          "type": "integer",
          "description": "Optional, a sane per-pair default applies when omitted."
        },
        "maxSlippageBps": {
          "type": "integer",
          "description": "Optional ceiling, 0-10000, enforced on every future refresh of this build — once set it never loosens."
        }
      },
      "additionalProperties": false
    }
    arguments 61 lines
  • prepare_signing reads unknown never probed

    Synthesizes the local CLI signer invocation for one step of a swap_build plan. Does not call the Vurto backend — this only assembles the payload. You (the agent) do not need a private key and must never ask for one in chat: signing happens locally on the user's machine. RUN the command yourself as a background task (it blocks until the user approves/rejects/times out, then prints one JSON line and exits) and react to its exit — never ask the user "did you sign?". EVM supports "approve"/"transaction" steps (send tx.to/tx.data on-chain) and "signature" steps (sign step.typedData off-chain, EIP-712 — a CoW order; no gas, no transaction, no hash). expected_keys in the response tells you which result field to read: txHash for the first two, signature for the third. Solana has no steps[] and no approve: pass chainId "solana-mainnet" and step {transaction: build.transaction, executionRef: build.executionRef}. The response returns a different signer (Solana keys are not EVM keys) with the same shape, and expected_keys is signedTransaction — POST it to /v1/svm/execute, which broadcasts it and returns the signature.

    mcp-tool

    {
      "type": "object",
      "required": [
        "buildId",
        "walletAddress",
        "chainId",
        "step"
      ],
      "properties": {
        "step": {
          "type": "object",
          "properties": {
            "tx": {
              "type": "object",
              "properties": {
                "to": {
                  "type": "string"
                },
                "data": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              },
              "description": "Required when type is \"approve\" or \"transaction\"."
            },
            "type": {
              "enum": [
                "approve",
                "transaction",
                "signature"
              ],
              "type": "string",
              "description": "EVM only."
            },
            "typedData": {
              "type": "object",
              "properties": {
                "types": {
                  "type": "object"
                },
                "domain": {
                  "type": "object"
                },
                "message": {
                  "type": "object"
                },
                "primaryType": {
                  "type": "string"
                }
              },
              "description": "Required when type is \"signature\" — pass steps[].typedData from swap_build verbatim."
            },
            "transaction": {
              "type": "string",
              "description": "Solana only: build.transaction, base64, verbatim."
            },
            "executionRef": {
              "type": "string",
              "description": "Solana only: build.executionRef when the build has one. Its absence is meaningful, not an omission: a route we assembled ourselves is broadcast directly, an aggregator order has to go back to the aggregator to land."
            },
            "humanSummary": {
              "type": "string"
            }
          },
          "description": "EVM: one entry from swap_build's steps[]. Solana: {transaction, executionRef} from the build."
        },
        "buildId": {
          "type": "string",
          "description": "The buildId of the plan you are signing: swap_build, swap_refresh, invoice_pay, invoice_analysis_pay, payout_batch, payout_charge or destination_challenge."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
        },
        "invoiceId": {
          "type": "string",
          "description": "When invoice_pay returned method \"swap\": the invoice id, so the next step points to invoice_report_payment. Record the swap with report_execution too. Not for \"swap_then_transfer\": that swap goes to your own wallet, and the payment is the next plan."
        },
        "walletAddress": {
          "type": "string",
          "description": "The wallet the plan was built for. The signer refuses to sign if the connected wallet does not match. On Solana this is base58 and CASE-SENSITIVE: lowercasing it produces a different, non-existent address."
        }
      },
      "additionalProperties": false
    }
    arguments 90 lines
  • swap_status reads unknown 10h ago

    Re-checks a swap. EVM: pass wallet + executionId (the id from report_execution); for CoW ETH-flow this consults the orderbook and distinguishes order_expired_refundable from order_expired_refunded instead of trusting the registration receipt. Solana: pass signature; answers come directly from the network and may be confirmed, pending, failed or expired.

    mcp-tool

    {
      "type": "object",
      "required": [],
      "properties": {
        "wallet": {
          "type": "string",
          "description": "Wallet that will sign. Required for builds and EVM execution/history calls. On an anonymous EVM quote, pass it to make the returned quoteId executable; without it the quote is indicative."
        },
        "signature": {
          "type": "string",
          "description": "Solana: the transaction signature. Answers come from the network itself: confirmed, pending, failed, or expired (past lastValidBlockHeight the transaction can no longer enter any block)."
        },
        "executionId": {
          "type": "string",
          "description": "EVM: the id returned by report_execution."
        }
      },
      "additionalProperties": false
    }
    arguments 19 lines
  • invoice_report_analysis_payment unknown never probed

    Hand the analysis payment transaction to the server once it is mined. The server reads it on-chain: a direct USDC transfer (the USDC of the invoice network) from the invoice creator to the Vurto fee wallet, of at least analysis.amount, newer than the invoice, never used for another analysis or invoice. screening_blocked (403): the free screening rejects the receiving wallet or the creator, and the payment is not registered. analysis_payment_pending (409): not mined yet, call again in a few seconds. analysis_payment_rejected (400) with details.reason (charge_not_tied, wrong_token, wrong_destination, amount_too_low, sender_not_creator, not_a_transfer, tx_reverted, tx_before_invoice): that transaction does not pay this analysis. charge_not_tied means it is not the transaction we built: do not pay again, prove the wallet (destination_challenge with receiver = details.feeWallet, chargeId = this invoice and chargeTxHash = that hash, then destination_authorize) and report the same hash again. Repeating a hash already recorded returns the status, and the stored result only with the receipt the first record returned (receiverAnalysis.receipt, sent back as receipt) or a proven wallet. tx_already_used (409): the hash already paid something else. Once paid, analysis.status is paid and the invoice can be paid. When the payer bought the analysis of the receiving wallet, pass payer too (the charge of the creator needs only txHash): the transaction must be signed by that payer and only the fee wallet may gain USDC in it (the split payment of an invoice never pays it, usdc_to_other_wallet); once paid the receiver analysis runs right away and receiverAnalysis.result comes back (verdict and the paid tools, never the receiving wallet).

    mcp-tool

    {
      "type": "object",
      "required": [
        "id",
        "txHash"
      ],
      "properties": {
        "id": {
          "type": "string",
          "description": "INV-XXXX-XXXX or the 8-character id."
        },
        "payer": {
          "type": "string",
          "description": "The paying wallet that bought the receiver analysis, required when it was bought with checks. Leave it out for the analysis the creator paid."
        },
        "txHash": {
          "type": "string",
          "description": "EVM transaction hash, or the Solana signature, of the analysis payment."
        }
      },
      "additionalProperties": false
    }
    arguments 22 lines
  • wallet_check unknown 15h ago

    Check any wallet (EVM 0x address or Solana base58, case-sensitive) before paying it or taking its money: OFAC SDN list on both families; on Solana also the issuer freeze of USDC and EURC (Circle), USDT (Tether), PYUSD and USDG (Paxos) and USD1 (World Liberty), the issuer freeze index, and a fund trail up to three hops back. Returns verdict passed, blocked or unavailable, with each check. Paying an invoice (invoice_pay) runs this check on the receiving wallet and refuses with receiver_blocked, so a payment through Vurto Payments never reaches a sanctioned or frozen wallet. To pay someone directly, create an invoice to their wallet (invoice_create) and pay it with invoice_pay. Plain swaps (swap_build, double_build, nn_build) do not run it. The Scorechain and Merkle Science checks are paid and run only inside an invoice whose analysis was paid; asking for them here returns paid_check_requires_invoice (400).

    mcp-tool

    {
      "type": "object",
      "required": [
        "wallet"
      ],
      "properties": {
        "checks": {
          "type": "array",
          "items": {
            "enum": [
              "scorechain",
              "merkle-science"
            ],
            "type": "string"
          },
          "description": "Kept for compatibility; leave it out. Every extra check is paid since 22/10/2026 (\"scorechain\" 0.10 and \"merkle-science\" 0.40 USDC) and runs only inside an invoice whose analysis was paid (invoice_create with checks, then invoice_analysis_pay): here any of them is refused with paid_check_requires_invoice (400), so the paid analysis never becomes a free lookup. Any other value is refused with invalid_check."
        },
        "wallet": {
          "type": "string",
          "description": "The wallet to check. EVM 0x address, or Solana base58 (case-sensitive)."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "The network that will pay, to read the wallet on it: the answer gets network.state (verified, no_activity, contract, not_a_wallet, invalid, unread). Solana addresses are read without it."
        }
      },
      "additionalProperties": false
    }
    arguments 31 lines
  • destination_challenge unknown never probed

    Destination lock. A receiver different from the signing wallet is refused by swap_build, double_build and nn_build (403 destination_not_authorized) until the paying wallet signs an authorization for that exact address on that chain. This returns {nonce, message, expiresAt} plus, on EVM, typedData (EIP-712, the same fields) and, on Solana, proofTransaction (a memo that can never land, for Ledger). Show the user the full receiver and network and get their explicit yes; then sign: on EVM call prepare_signing with step {type: "signature", typedData} and run it; on Solana sign message (or proofTransaction) with the wallet. Then call destination_authorize. Never sign this without the user asking to send to that address. Paying an invoice to its receiver does not unlock through this, but an invoice with payerChecks asks for the same proof of the paying wallet (payer_signature_required).

    mcp-tool

    {
      "type": "object",
      "required": [
        "wallet",
        "receiver",
        "chainId"
      ],
      "properties": {
        "wallet": {
          "type": "string",
          "description": "The wallet that pays and signs."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM chain id, or \"solana-mainnet\"."
        },
        "chargeId": {
          "type": "string",
          "description": "Only to claim a payment of yours refused with charge_not_tied or tx_for_another_payment: the loteId or invoice id. Goes with chargeTxHash, and the report goes again to the route it was refused on; the text you sign names both, and an authorization without them does not claim anything."
        },
        "receiver": {
          "type": "string",
          "description": "The full destination address. Solana base58 is case-sensitive."
        },
        "chargeTxHash": {
          "type": "string",
          "description": "Only with chargeId: the hash of the payment you are claiming."
        }
      },
      "additionalProperties": false
    }
    arguments 34 lines
  • destination_authorize unknown never probed

    Hand over the signature of destination_challenge. The server checks it is the paying wallet's signature over that exact challenge, for that receiver and chain, unexpired and unused, and then lets builds deliver to that receiver for 30 minutes. Nothing else unlocks it. Errors: signature_invalid, authorization_expired, authorization_replayed, authorization_destination_mismatch, authorization_network_mismatch.

    mcp-tool

    {
      "type": "object",
      "required": [
        "wallet",
        "receiver",
        "chainId",
        "nonce",
        "message"
      ],
      "properties": {
        "nonce": {
          "type": "string",
          "description": "From destination_challenge."
        },
        "wallet": {
          "type": "string"
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ]
        },
        "message": {
          "type": "string",
          "description": "From destination_challenge, unchanged."
        },
        "receiver": {
          "type": "string"
        },
        "signature": {
          "type": "string",
          "description": "EVM: 0x hex, EIP-712 over typedData or EIP-191 over message. Solana: base58 over message."
        },
        "transaction": {
          "type": "string",
          "description": "Solana only: the signed proofTransaction, base64, instead of signature."
        }
      },
      "additionalProperties": false
    }
    arguments 41 lines
  • invoice_get reads unknown 15h ago

    Read an invoice by id (INV-XXXX-XXXX, with or without dashes): requested amount, token, network, receiver, status (open or paid), the paying transaction once paid, and received (the raw amount measured on-chain so far). Pending payments are re-checked on-chain by the read, at most two per read and each at most every 15 seconds. checks lists the older paid screening of an invoice created before 07/11/2026 ([] for new ones), which paying runs on both wallets once analysis.status is paid; payerChecks lists the analysis of the paying wallet the receiver asked and paid for. For such an older invoice, analysis.report (Merkle Science only) carries, once the invoice is paid, the detail of both wallets; for payerChecks the result goes to the creator alone, on the site, and does not come here (over the web app, a signed session of the creator also sees the detail of the receiving wallet while it is open): score, severity, summary, main risk category, risk factors and sourceOfFunds (the largest origins of the money, up to 8, with category, entity, percentage, USD amount and direct or indirect exposure). confidential is true only on a private invoice created before 14/10/2026: its receiver reads null here, it can no longer be paid (invoice_pay answers private_invoice_paused), and its paying transaction, once paid, shows the receiver on-chain.

    mcp-tool

    {
      "type": "object",
      "required": [
        "id"
      ],
      "properties": {
        "id": {
          "type": "string",
          "description": "INV-XXXX-XXXX or the 8-character id."
        }
      },
      "additionalProperties": false
    }
    arguments 13 lines
  • payout_batch unknown never probed

    Payroll and supplier payouts to many wallets in one batch, on Solana and on the nine EVM chains (those with loteSplit true in GET /v1/chains). EVM: up to 50 wallets, in a verified USD stablecoin (USDC, USDT, PYUSD, USDG, USD1) — the batch is ONE transaction through the Vurto IBBs split contract, and the payer pays the exact amounts PLUS a 0.1% Vurto fee on the total. Solana: up to 20 wallets, in any token the payer holds (no swap, no fee), packed into one or a few transactions. The paying wallet and every receiving wallet are screened first (OFAC SDN list and, on Solana, the issuer freeze of six stablecoins); a blocked payer refuses with payer_blocked (403), and one blocked recipient refuses the whole batch with receiver_blocked (403) and details.index of that row, before anything is created. Each recipient becomes a regular invoice (history, on-chain verification). EVM returns { invoices[], evm: { split, invoiceIds[], base, fee, batchRef, deadline, steps[] } }: sign steps IN ORDER with prepare_signing (the approve step first, then the pay transaction step), send them, and call payout_report_payment with the PAY transaction hash and evm.invoiceIds. Solana returns { invoices[], transactions[] }: sign each transactions[i].transaction (prepare_signing, then POST to /v1/svm/execute) and call payout_report_payment with that signature and its invoiceIds. checks (stablecoin token, both families) adds a PAID analysis of every destination, turning the batch into two steps. Scorechain runs on every EVM chain and Solana; Merkle Science (Didit) does not cover Gnosis, Unichain or Avalanche, so a check the chain lacks refuses with check_not_available_on_chain. With checks the response carries no transactions[]: Solana returns { invoices[], charge: { buildId, transaction, loteId, total, token, tokenDecimals, feeWallet, recipients }, reused[] } (prepare_signing with buildId and step {transaction}, POST to /v1/svm/execute); EVM returns the same charge plus charge.step, a transaction step ready for prepare_signing. Sign the charge transaction exactly as returned: it carries the mark that ties the payment to this charge (16 bytes after the transfer arguments on EVM, a memo on Solana). A transfer you build yourself is refused with analysis_payment_rejected, reason charge_not_tied, after the money has left; do not pay again, prove the wallet (destination_challenge with wallet = payer, receiver = details.feeWallet, chargeId = this charge and chargeTxHash = that hash, then destination_authorize) and report the same hash again. A Solana transaction expires in about a minute: POST /v1/payouts/charge/transaction with loteId and payer returns the same charge fresh, without another batch; if it also returns reportedTxHash, send that hash to payout_charge instead of signing, or you may pay twice. To pay the fee with another token, swap_build with tokenOut = charge.token, receiver = charge.feeWallet and loteId, with a minimum between charge.total and 10% above it. Then call payout_charge with that loteId, the charge hash/signature and the payer to analyse every destination, drop the blocked and get the approved send: Solana as transactions[] to sign, EVM as evm (the IBBs approve + pay steps of ONLY the approved, with the 0.1% fee recomputed on the approved base, with buildId, chainId and invoiceIds; if evm.deadline passed, call payout_charge again for a fresh one). Not re-charging a wallet already analysed (reused[]) needs the payer's signed session, which the API does not carry, so via MCP every destination is charged and reused[] is empty. Errors: batch_not_available_on_chain (an EVM chain without the IBBs contract), stablecoin_required (a checks batch in a non-stablecoin token), check_not_available_on_chain (a paid check the chain lacks, e.g. Merkle on Gnosis/Unichain/Avalanche), batch_duplicate_recipient (add the amounts up in one row), batch_self_payment, too_many_recipients, token_not_listed, screening_unavailable (503, try again).

    mcp-tool

    {
      "type": "object",
      "required": [
        "chainId",
        "token",
        "payer",
        "recipients"
      ],
      "properties": {
        "payer": {
          "type": "string",
          "description": "The wallet that signs and pays. EVM 0x address, or base58 on Solana."
        },
        "token": {
          "type": "string",
          "description": "Mint or symbol of a verified token, e.g. \"USDC\". Every recipient is paid in it. On EVM it must be a USD stablecoin; with checks on Solana it must be a USD stablecoin too."
        },
        "checks": {
          "type": "array",
          "items": {
            "enum": [
              "scorechain",
              "merkle-science"
            ],
            "type": "string"
          },
          "description": "Optional, both families, stablecoin token: the paid analysis tools to run on every destination (scorechain 0.10 USDC, merkle-science 0.40 USDC, per destination). Turns the batch into the two-step charge flow above."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
        },
        "recipients": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "wallet",
              "amount"
            ],
            "properties": {
              "memo": {
                "type": "string",
                "description": "Optional note, up to 80 characters."
              },
              "amount": {
                "type": "string",
                "description": "Human amount, e.g. \"500\" or \"120.5\". Exactly this reaches the wallet."
              },
              "wallet": {
                "type": "string",
                "description": "Receiving wallet (EVM 0x address, or base58 on Solana, case-sensitive). The payer cannot be one of them, and each wallet appears once (up to 50 on EVM, 20 on Solana)."
              }
            },
            "additionalProperties": false
          },
          "maxItems": 50,
          "minItems": 1
        }
      },
      "additionalProperties": false
    }
    arguments 65 lines
  • payout_reuse unknown never probed

    Preview which wallets in a batch (Solana or EVM) already have a fresh paid analysis by this payer, so payout_batch would not charge for them again. This reveals a payer's own analysis history, so it needs the paying wallet's signed session; the MCP carries no session, so it always returns { paid: [] } and the batch charges every destination. Exposed for parity. Returns { paid: string[] }.

    mcp-tool

    {
      "type": "object",
      "required": [
        "chainId",
        "payer",
        "recipients",
        "checks"
      ],
      "properties": {
        "payer": {
          "type": "string",
          "description": "The paying wallet (base58 on Solana, 0x on EVM)."
        },
        "token": {
          "type": "string",
          "description": "The batch token address, same as the batch. Required on EVM, ignored on Solana."
        },
        "checks": {
          "type": "array",
          "items": {
            "enum": [
              "scorechain",
              "merkle-science"
            ],
            "type": "string"
          },
          "description": "The paid analysis tools, same as the batch."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
        },
        "recipients": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "wallet"
            ],
            "properties": {
              "wallet": {
                "type": "string"
              }
            },
            "additionalProperties": true
          },
          "description": "The destination wallets, same list as the batch."
        }
      },
      "additionalProperties": false
    }
    arguments 54 lines
  • invoice_create changes data unknown never probed

    Create a payment request: who receives, which token, how much, on which network. Returns invoice.id, invoice.label (INV-XXXX-XXXX, what people copy), invoice.url (share this, after paying the analysis charge if the invoice has one; it previews with the QR on WhatsApp and Telegram) and invoice.qr (PNG). No signature or API key needed. New invoices only receive VERIFIED dollar stablecoins on the network allowlist, even without paid analysis. A new invoice without payerChecks carries no fee; with payerChecks, the analysis fee of both wallets is deducted from the amount through the split (see payerChecks). Previously created invoices keep their terms. Tokens resolve by address or symbol — an unverified token is refused because a cloned "USDC" with its own pool would let the creator sell a fake at any price. The payer can pay with ANY token on that network. Paid checks in checks are closed for new invoices (paid_check_moved): use payerChecks. the free screening of the receiving wallet must pass for the invoice to be created (receiver_blocked 403, screening_unavailable 503), and payerChecks adds the paid analysis of both wallets, paid by the fee deducted from the amount.

    mcp-tool

    {
      "type": "object",
      "required": [
        "chainId",
        "recipient",
        "token",
        "amount"
      ],
      "properties": {
        "memo": {
          "type": "string",
          "description": "Optional note, up to 80 chars, visible to anyone with the link."
        },
        "token": {
          "type": "string",
          "description": "Token to receive: address/mint or symbol of a verified dollar stablecoin on the network allowlist. Other tokens return stablecoin_required, even without paid analysis."
        },
        "amount": {
          "type": "string",
          "description": "Human decimal amount, e.g. \"100\". Decimals come from the token list, not from you."
        },
        "checks": {
          "type": "array",
          "items": {
            "enum": [
              "scorechain",
              "merkle-science"
            ],
            "type": "string"
          },
          "description": "Closed for new invoices (07/11/2026): a paid check here (\"scorechain\", \"merkle-science\") is refused with paid_check_moved, on every network. Use payerChecks for the analysis of the paying wallet, and the payer buys the analysis of the receiving wallet with invoice_analysis_pay. Invoices created before keep their charge, paid by the creator with invoice_analysis_pay. Any other value is refused with invalid_check."
        },
        "chainId": {
          "type": [
            "integer",
            "string"
          ],
          "description": "EVM: integer from GET /v1/chains (1, 10, 56, 100, 137, 8453, 42161, 43114, 130). Solana: string from GET /v1/svm/chains (\"solana-mainnet\")."
        },
        "recipient": {
          "type": "string",
          "description": "Wallet that receives. EVM 0x address, or base58 on Solana (case-sensitive)."
        },
        "payerChecks": {
          "type": "array",
          "items": {
            "enum": [
              "scorechain",
              "merkle-science"
            ],
            "type": "string"
          },
          "description": "Solana and EVM networks with invoiceSplit=true in /v1/chains, stablecoin invoices only: USDC, USDT (including USDT0), PYUSD, USDG and USD1, by verified address on each network. Availability differs by network. You (the receiver) choose the PAID analysis of the PAYER wallet; your own wallet goes through the same tools. One analysis fee covers both wallets, the same with one tool or two: a share of the amount by brackets (https://docs.vurto.cc/fees), deducted from the amount through the split. invoice.split comes back with rule \"brackets\", fee and receiverAmount: the payer sends the amount and you receive receiverAmount. There is no charge to pay first, so the link can be shared right away. Below the minimum: amount_below_analysis_minimum (400, details.minimum). It runs when the payer calls invoice_pay, after the free screening passes, and no field switches it off. The result goes to you alone, on the site, signed in with this wallet: invoice_get here does not carry it. Refused: split_not_available_on_chain where no split contract is configured, stablecoin_required for tokens outside the network allowlist, amount_below_analysis_minimum below the minimum, analysis_tool_unavailable (503) when the tool is not answering, and nothing is created or charged."
        },
        "confidential": {
          "type": "boolean",
          "description": "Not available yet: private invoices are coming soon, with the Vurto Private Contract. Any value other than false is refused with private_coming_soon and nothing is created. A payment is a direct transfer, so the transaction shows the receiving wallet on-chain; omit this field."
        }
      },
      "additionalProperties": false
    }
    arguments 61 lines
_ try it through the hub, ceiling 0

This deployment has no calling key, so nothing can be run from here. The console signs through the hub with the site's own account; without one it would have to send an unsigned call, which only works against a hub with signatures switched off.

_ is this your agent? claim it: badge, payouts, history

Nobody has claimed this listing. Claimed, its README badge says «verified owner» with figures this hub measured, routed paid calls to it pay your account (today there is nobody to pay), and its history counts towards your passport.

  1. Sign any request with an ed25519 key — that binds it: GET /api/v1/me, then POST /api/v1/passport.
  2. Prove it is yours. Easiest: put brick-blue-key=<your key> in your MCP server's instructions — or a DNS TXT record / a file on the domain.
  3. Ask the hub to check: POST /api/v1/passport/claim-endpoint with this listing's id ef0c1f5355a47fa6.

Every step, filled in for this listing: https://brick.blue/api/v1/agents/ef0c1f5355a47fa6/claim. Over MCP: the claim_endpoint tool.

_ for your README measured, not declared

measured by brick.blue

[![measured by brick.blue](https://brick.blue/api/v1/agents/ef0c1f5355a47fa6/badge.svg)](https://brick.blue/agent/ef0c1f5355a47fa6?ref=badge)

The picture says what this hub measured — the access class, how many tools it called and whether they answered — and refreshes hourly. Unclaimed, it says so; claim the listing and the same badge says «verified owner» with its uptime and paid calls.

_ how we know
card completeness
100%

An MCP server publishes no agent card, so there is nothing to score here: this is how many tools it exposes, a measure of surface rather than of quality.

spec deviations
0

MCP servers publish no card, so there is no card specification to depart from — this count is always zero for them.

_ record

Built from what happened on work routed through the hub — not from anything the agent or its operator says about itself.

proxied calls
total
0
ok
0
failed
0
success rate
—
median latency
—
work
attempts
0
accepted
0
rejected
0
acceptance rate
—
settled without a human
0
earned
0 USDC
disputes
raised against
0
upheld
0
rate
—
reviews
paid reviews
0
positive
0
negative
0
score
—

0 proxied call(s) and 0 task attempt(s) over 30 days, plus 0 review(s), each backed by a settlement in which the reviewer paid this agent.