reference
errors & rate limits
A blocked payment is not an error: it is a 200 with status denied. Errors are for bad keys, bad input, missing objects and frozen agents.
business outcomes (200)
Branch on status, never on the text of reason:
| status | from | what to do |
|---|---|---|
paid | pay | Done. Keep transactionId. |
initiated | send_transfer | Transfer submitted. Keep paymentId. |
pending_approval | pay, send_transfer | Tell the user a human must approve; poll get_request_status later. Do not retry. |
denied | pay, send_transfer | The mandate forbids it. Do not retry or split; report reason. |
declined_by_bank | pay, send_transfer | The issuer refused: InsufficientFunds, CardSpendingLimitExceeded or CardNotActivated. Ask an admin. |
http errors
Errors return a JSON body {"error": "…"}, sometimes with details.
| code | when | example error |
|---|---|---|
400 | Invalid input (schema, IBAN, amount, email), a request already decided, or a sandbox balance above 1 000 000 EUR. | IBAN invalide, Demande déjà executed |
401 | Missing or invalid key, or revoked agent. | Clé agent invalide, Clé admin invalide |
403 | Agent is frozen or inactive, or an operator-only route called with a sandbox key. | Agent gelé par l'entreprise : aucune dépense possible |
404 | Agent, request or workspace not found (or not yours). | Demande introuvable |
409 | Account not ready on the banking side. | |
429 | Sandbox limit reached: signups, workspaces per email, 25 agents per workspace. | Too many signups, try again in an hour |
500 | Unexpected error on our side. | Erreur interne |
502 | The banking partner returned an error; details has its payload. |
{
"error": "Données invalides",
"details": [
{
"code": "too_small",
"minimum": 0,
"path": [
"amount"
],
"message": "Too small: expected number to be >0"
}
]
}status field.mcp errors
| case | shape |
|---|---|
| Bad or missing key | HTTP 401, JSON-RPC error.code -32001 |
| Arguments fail the tool schema | Result with isError: true, text starting MCP error -32602: Input validation error |
| Tool failed (frozen, not found…) | Result with isError: true and {"error": "…"} as text |
| Unknown tool | JSON-RPC error; the tool is not in your profile (agent vs admin key). |
{
"jsonrpc": "2.0",
"error": {
"code": -32001,
"message": "Clé Nostro invalide (Bearer nst_... pour un agent, nsa_... pour l'admin d'un espace)"
},
"id": null
}rate limits
v0.1 has no per-key request quota on MCP and REST calls; the sandbox is for development and demos, under fair use. Hard limits today: signup 10 per hour per IP and 500 per hour overall, 3 sandbox workspaces per email, 25 active agents per workspace, 1 000 000 EUR max sandbox balance. Plan for request quotas anyway:
- On
429, wait forRetry-Afterif present, otherwise back off exponentially (1 s, 2 s, 4 s, max 30 s). - Do not poll
get_request_statusin a tight loop: humans take minutes. Every 30 to 60 seconds is plenty.
retries and idempotency
pay has no idempotency key in v0.1. If a call times out, do not blindly retry: call list_my_activity first and check whether the payment was recorded. Retrying a denied or pending_approval result is never useful.