docs
fren get sandbox key

reference

rest api reference

The same capabilities as the MCP tools, over plain HTTPS and JSON. Agents use /v1/agent/*, admins use /api/*, on one base URL.

basics

itemvalue
base URLhttps://mcp.nostro.ag
authAuthorization: Bearer nst_… on /v1/agent/*, Bearer nsa_… on /api/*
formatJSON in, JSON out. Send content-type: application/json on POST.
amountsNumbers in EUR in requests; money objects {value, currency} with string values in balances.
CORSOpen (*). Keys are bearer secrets: call from servers, not browsers.
healthGET /health → {"ok":true,"bankMode":"…"}
example
curl -s -X POST https://mcp.nostro.ag/v1/agent/pay \
  -H "Authorization: Bearer $NOSTRO_AGENT_KEY" \
  -H "content-type: application/json" \
  -d '{"amount":49,"merchant":"Vercel","mcc":"5734","description":"Pro plan"}'

sandbox signup

POST /api/sandbox/signup

POSThttps://mcp.nostro.ag/api/sandbox/signup

Public, no auth. Creates a sandbox workspace funded with 10 000 EUR of fake money, an admin key and a demo-agent key (per payment 500, per day 2 000, approval above 250). Keys are returned once.

nametypedescription
emailstringrequiredWhere we can reach you about the preview.
companystringoptionalCompany name, used for the workspace.
langstringoptional"en" (default) or "fr": language of the demo agent and of limit messages.
body
{
  "email": "you@company.com",
  "company": "Acme",
  "lang": "en"
}
201 Created
{
  "workspace_id": "ws_7c1e9a42b0d3",
  "admin_key": "nsa_9Hc2••••••••••••••••••••••••",
  "agent": {
    "id": "agt_3f2b8d10",
    "name": "demo-agent",
    "key": "nst_k3Jd••••••••••••••••••••••••",
    "policy": {
      "currency": "EUR",
      "perTxMax": 500,
      "dailyMax": 2000,
      "monthlyMax": 5000,
      "approvalAbove": 250,
      "allowedMccs": [],
      "blockedMerchants": [],
      "transfersEnabled": false,
      "transferApprovalAbove": 0
    }
  },
  "mcp_url": "https://mcp.nostro.ag/mcp",
  "balance": {
    "amount": 10000,
    "currency": "EUR",
    "fake": true
  },
  "sandbox": true
}
limitvalueon breach
sandbox workspaces per email3429
signups per IP10 per hour429
signups overall500 per hour429
invalid email400

Browsers can call this endpoint only from nostro.ag and docs.nostro.ag (CORS). Server-side and terminal calls are unaffected.

GET /api/sandbox/stats

GEThttps://mcp.nostro.ag/api/sandbox/stats

Public, no auth, cached 30 s. Aggregate counters of the public sandbox (test domains excluded).

200 OK
{
  "workspaces": 128,
  "agents": 241,
  "payments": 1873,
  "volume_eur": 96412.5
}

agent endpoints

Key: nst_…. Every call is scoped to the agent that owns the key.

GET /v1/agent/wallet

GEThttps://mcp.nostro.ag/v1/agent/wallet

Remaining budget (day, month), caps, card status and the available balance of the company account. Agents are instructed to call it before any spend. Same as MCP get_wallet.

200 OK
{
  "agent": {
    "id": "agt_3f2b8d10",
    "name": "demo-agent",
    "status": "active"
  },
  "card": {
    "id": "vcard_5e1d77a0c4b2",
    "maskedNumber": "4970 •••• •••• 3182",
    "status": "Enabled"
  },
  "accountAvailable": {
    "value": "10000.00",
    "currency": "EUR"
  },
  "budget": {
    "currency": "EUR",
    "perTxMax": 500,
    "approvalAbove": 250,
    "dailyRemaining": 2000,
    "monthlyRemaining": 5000
  },
  "transfersEnabled": false
}

POST /v1/agent/pay

POSThttps://mcp.nostro.ag/v1/agent/pay

Pays a merchant with the agent's virtual card. Evaluated against the mandate first: executed, blocked, or held for human approval. Same as MCP pay.

nametypedescription
amountnumberrequiredAmount in EUR, > 0. Rounded to 2 decimals, e.g. 19.99.
merchantstringrequiredMerchant name. Matched against blockedMerchants.
mccstringoptionalMerchant category code, exactly 4 digits, e.g. 5734. Required when the mandate has allowedMccs.
descriptionstringoptionalWhat the spend is for. Stored in the audit log.
body
{
  "amount": 49,
  "merchant": "Vercel",
  "mcc": "5734",
  "description": "Pro plan, November"
}
200 OK
{
  "status": "paid",
  "transactionId": "vtx_883b5610e2a1",
  "amount": 49,
  "merchant": "Vercel"
}

POST /v1/agent/transfer

POSThttps://mcp.nostro.ag/v1/agent/transfer

Sends a SEPA transfer from the company account, only if the mandate enables transfers. Usually held for human approval. Same as MCP send_transfer.

nametypedescription
amountnumberrequiredAmount in EUR, > 0.
ibanstringrequiredBeneficiary IBAN. Spaces are stripped; must match ^[A-Z]{2}\d{2}[A-Z0-9]{10,30}$.
beneficiaryNamestringrequiredBeneficiary name.
labelstringoptionalTransfer label, max 140 characters. Defaults to "Nostro <agent name>".
body
{
  "amount": 1200,
  "iban": "FR7630006000011234567890189",
  "beneficiaryName": "Acme SAS",
  "label": "Invoice 2026-114"
}
200 OK
{
  "status": "pending_approval",
  "requestId": "req_51c0aa9e",
  "reason": "Virement soumis à approbation humaine",
  "message": "Demande transmise à un humain de l'entreprise. Vérifie son statut avec get_request_status."
}

GET /v1/agent/requests/:id

GEThttps://mcp.nostro.ag/v1/agent/requests/:id

Status of a spend held for human approval. Agents can only read their own requests. Same as MCP get_request_status.

200 OK
{
  "id": "req_ef5c846c",
  "kind": "card_payment",
  "amount": 320,
  "status": "executed",
  "reason": "Au-dessus du seuil d'approbation (250 €)",
  "result": {
    "amount": 320,
    "status": "paid",
    "merchant": "AWS",
    "transactionId": "vtx_acf5376d09be"
  },
  "createdAt": "2026-11-05T09:19:33.478Z",
  "decidedAt": "2026-11-05T09:20:41.561Z"
}

GET /v1/agent/activity

GEThttps://mcp.nostro.ag/v1/agent/activity

The agent's last 50 events, newest first. Same as MCP list_my_activity.

200 OK
[
  {
    "id": 7,
    "workspace_id": "ws_7c1e9a42b0d3",
    "agent_id": "agt_3f2b8d10",
    "type": "card_payment",
    "amount": 320,
    "counterparty": "AWS",
    "decision": "executed",
    "reason": null,
    "bank_ref": "vtx_acf5376d09be",
    "created_at": "2026-11-05T09:20:41.560Z",
    "agent_name": "demo-agent"
  },
  {
    "id": 5,
    "workspace_id": "ws_7c1e9a42b0d3",
    "agent_id": "agt_3f2b8d10",
    "type": "card_payment",
    "amount": 900,
    "counterparty": "Apple",
    "decision": "denied",
    "reason": "Dépasse le plafond par transaction (500 €)",
    "bank_ref": null,
    "created_at": "2026-11-05T09:18:02.491Z",
    "agent_name": "demo-agent"
  }
]

admin endpoints

Key: nsa_…. Scoped to the admin key's workspace.

methodpathdescriptionMCP
GET/api/overviewAccount, balance, number of active agents, pending approvals and spend this month.overview
GET/api/agentsEvery non-revoked agent with its card, mandate and current spend.list_agents
POST/api/agentsCreates an agent with its own virtual card in the company's name, its mandate and its API key. The key is returned once and never again.create_agent
GET/api/agents/:idOne agent (card, mandate, spend).·
POST/api/agents/:id/refreshRe-reads the card status from the issuer.·
POST/api/swan/bootstrapOperator only (owner workspace). Returns 403 with a sandbox key.·
POST/api/agents/:id/policyPatches an agent's mandate. Only the fields you send change; the rest is kept. Changing monthlyMax also updates the card limit.update_agent_policy
POST/api/agents/:id/freezeKill switch: blocks every spend of the agent immediately. Reversible.freeze_agent
POST/api/agents/:id/unfreezeRe-activates a frozen agent.unfreeze_agent
POST/api/agents/:id/revokeRevokes the agent's key and cancels its card. Irreversible.revoke_agent
GET/api/requests?status=Requests by status: pending (default), executed, failed, rejected or all. Max 100.list_pending_approvals
POST/api/requests/:id/approveApproves a pending request and executes it right away. One decision per request, even with concurrent clicks.approve_request
POST/api/requests/:id/rejectRejects a pending request. Nothing is charged.reject_request
POST/api/fundSandbox only: credits the workspace's virtual ledger (simulated incoming SEPA transfer, fake euros). {"amount":5000}fund_account
GET/api/events?agentId=&limit=Every decision and operation in the workspace, newest first, optionally for one agent. Default limit 100, max 500.audit_log

Bodies and responses are the same as the MCP tools, with one difference: POST /api/agents nests the mandate under policy, where the MCP tool takes the fields flat.

POST /api/agents · body
{
  "name": "procurement-bot",
  "purpose": "Buys SaaS seats",
  "policy": {
    "perTxMax": 200,
    "dailyMax": 600,
    "monthlyMax": 3000,
    "approvalAbove": 100,
    "allowedMccs": [
      "5734",
      "7372"
    ]
  }
}
201 Created
{
  "agent": {
    "id": "agt_91ad04c2",
    "name": "procurement-bot",
    "purpose": "Buys SaaS seats",
    "status": "active",
    "keyPrefix": "nst_Qm7v",
    "card": {
      "id": "vcard_0c44e1b9a7d0",
      "status": "Enabled",
      "maskedNumber": "4970 •••• •••• 7745",
      "consentUrl": null
    },
    "policy": {
      "currency": "EUR",
      "perTxMax": 200,
      "dailyMax": 600,
      "monthlyMax": 3000,
      "approvalAbove": 100,
      "allowedMccs": [
        "5734",
        "7372"
      ],
      "blockedMerchants": [],
      "transfersEnabled": false,
      "transferApprovalAbove": 0
    },
    "spend": {
      "today": 0,
      "month": 0
    },
    "createdAt": "2026-11-05T09:12:04.118Z"
  },
  "apiKey": "nst_Qm7v••••••••••••••••••••••••"
}
POST /api/agents/:id/policy · body
{
  "approvalAbove": 100,
  "blockedMerchants": [
    "casino"
  ]
}