Skip to content

AI agents and MCP

Any AI agent can use Xaalis: learn the API, open a sandbox account, collect Wave and Orange Money payments, refund, bill subscriptions and pay people out — with little or no human help, and without ever being able to move live money beyond what a human allowed.

You want… Use
an assistant (Claude, ChatGPT, Cursor, VS Code, Codex…) to operate Xaalis for you the MCP server — connect your client
a coding agent to integrate Xaalis into your app the Agent Skills (or the Claude Code plugin) + the MCP server for docs and test objects
your own agent (OpenAI, Anthropic, Vercel AI SDK, LangChain, Python) to call Xaalis the tool catalog — frameworks

LLM-readable docs: /llms.txt · /llms-full.txt.

What an agent can do — the credential decides

Section titled “What an agent can do — the credential decides”

The MCP server only lists the tools the connected credential allows, so a model can’t call what it can’t see — the first defence against a prompt injection asking it to “just send a payout”. The API enforces the same limits again.

Credential Tools
none xaalis_whoami, xaalis_search_docs, xaalis_sandbox_signup (creates a sandbox account; the session then uses it)
sk_test_… sandbox everything, with fake money: payments + xaalis_simulate_payment, refunds, subscriptions + xaalis_advance_subscription, payouts, agent-wallet setup
sk_live_… read everything; create payments and subscriptions (money in); cancel subscriptions; disable agent wallets. No payouts. Refunds only if a human turned them on
rk_test_… / rk_live_… restricted key, or an OAuth sign-in the same, narrowed to the scopes a human granted in the dashboard (e.g. payments:read + payments:write only). Refunds appear only if refunds:write was granted
ak_test_… / ak_live_… agent wallet its own policy and balance, and payouts within the per-payout cap, daily cap, recipient list and balance a human set

Test credentials go to the sandbox API, live ones to production — automatically.

Least privilege: for an agent in production, prefer a restricted key (dashboard → API keys → restricted, pick the scopes) or an OAuth sign-in over a full sk_live_ key. Scopes: payments:read, payments:write, refunds:write, subscriptions:read, subscriptions:write, payouts:read, balance:read, webhooks:read, agent_wallets:read, agent_wallets:write (and payouts:write, webhooks:write, which the MCP tools don’t use).

Live refunds with a full sk_live_ key are off unless the human who sets up the connection turns them on: header X-Xaalis-Allow-Live-Refunds: true (hosted) or XAALIS_ALLOW_LIVE_REFUNDS=true (local). With a restricted key or OAuth, granting refunds:write is that decision. The model can change neither.

Money out is done only by agent wallets: a separate balance (the agent’s total budget), a per-payout cap, an optional daily cap and an allow-list of phone numbers, with a key that can do nothing else. Retrying the same action_id never pays twice. In production, only a dashboard owner can create, fund and issue keys for a live agent wallet — never an API key, so an agent can’t fund itself. See Agent wallets.

The server sends these as MCP instructions; the skills repeat them.

  1. Amounts are whole XOF integers (15000), never decimals.
  2. Every write takes an idempotency_key derived from the business action; retries reuse it.
  3. A payment is paid only when it reads succeeded (or a signed webhook says so) — never because of a redirect.
  4. Test keys are fake money. With a live key, confirm amount and purpose with the human before any write.
  5. Money goes out only through agent wallets.
  6. outcome_unknown: true → read the object or retry with the same key; never create a second one.
  7. Secret keys stay in environment variables or a secret store — never in chat, code or logs.

Connect without a key. The agent calls xaalis_sandbox_signup with an email and a business name and gets a sandbox account (sk_test_… key + webhook secret). The same session switches to it, so the agent can go straight on: create a payment, simulate the customer paying, refund it, set up a subscription.

  • Local server: the session keeps the key until the process stops.
  • Hosted server: connect to https://mcp.xaalis.org/sandbox with no credential. The session (Mcp-Session-Id) keeps the sandbox key in memory for up to 30 idle minutes. Clients set to “no authentication” (ChatGPT, claude.ai) use this; the sandbox tools are listed from the start and answer signup_required until the signup.
  • To keep the account, store the returned secret_key as XAALIS_API_KEY and reconnect with it.

Going live always needs a human: identity checks (KYC), approval, then a live key.

Hosted endpoint Credential
https://mcp.xaalis.org/mcp Authorization: Bearer <key> (sk_, rk_, ak_), or OAuth: without a credential it answers 401 and OAuth-capable clients open the Xaalis sign-in, where you pick the account, test or live, and the scopes
https://mcp.xaalis.org/sandbox none — the zero-human sandbox session

Local: npx -y @xaalis/mcp (Node 20+) with the key in XAALIS_API_KEY. Omit the key for the zero-human start.

Terminal window
claude mcp add --transport http xaalis https://mcp.xaalis.org/mcp --header "Authorization: Bearer $XAALIS_API_KEY"
# or local:
claude mcp add --env XAALIS_API_KEY=$XAALIS_API_KEY --transport stdio xaalis -- npx -y @xaalis/mcp

Or install the plugin (MCP server + skills; the key is asked once and kept in your OS credential store):

/plugin marketplace add <path-or-repo-with-integrations/ai>
/plugin install xaalis@xaalis

Project .mcp.json (shared with your team — the key stays in each person’s environment):

{
"mcpServers": {
"xaalis": { "type": "http", "url": "https://mcp.xaalis.org/mcp", "headers": { "Authorization": "Bearer ${XAALIS_API_KEY}" } }
}
}

Local server — claude_desktop_config.json (macOS ~/Library/Application Support/Claude/, Windows %APPDATA%\Claude\):

{ "mcpServers": { "xaalis": { "command": "npx", "args": ["-y", "@xaalis/mcp"], "env": { "XAALIS_API_KEY": "sk_test_…" } } } }

Remote custom connector (Customize → Connectors → Add custom connector):

  • your account: URL https://mcp.xaalis.org/mcp — Claude opens the Xaalis sign-in (OAuth). You choose the account, test or live, and what the connector may do (scopes). Withdrawing that consent takes effect immediately.
  • no account yet: URL https://mcp.xaalis.org/sandbox with no sign-in — the zero-human sandbox session.

Plugins → Add → Add custom MCP server (no developer mode needed any more):

  • your account: URL https://mcp.xaalis.org/mcp, authentication OAuth — ChatGPT discovers the Xaalis sign-in by itself; you choose the account, test or live, and the scopes.
  • no account yet: URL https://mcp.xaalis.org/sandbox, No authentication — the agent searches the docs, opens a sandbox account and uses it in that conversation.

Checked end to end with Claude.ai and ChatGPT on 2026-10-14:

  • Only an owner of the business can authorize a connector; a teammate with another role sees “Autorisation non disponible”.
  • You pick the business and test or live (live only once the business is activated), then untick any permission you don’t want to give — e.g. keep payments:read, balance:read and payments:write, and leave refunds, payouts and agent-wallet writes off. The connector gets exactly what stays ticked.
  • Approve within 10 minutes of clicking Connect; after that the request expires (“Erreur de continuation OAuth”) and you start again from Connect.
  • Access tokens last 5 minutes and are renewed in the background (offline_access). Settings → Applications & IA → Révoquer l’accès cuts the connector off at once — its next call fails even with an unexpired token.

.cursor/mcp.json (project) or ~/.cursor/mcp.json:

{
"mcpServers": {
"xaalis": { "url": "https://mcp.xaalis.org/mcp", "headers": { "Authorization": "Bearer ${env:XAALIS_API_KEY}" } }
}
}

Local instead: { "command": "npx", "args": ["-y", "@xaalis/mcp"], "env": { "XAALIS_API_KEY": "${env:XAALIS_API_KEY}" } }.

.vscode/mcp.json — note the top-level key servers; VS Code asks for the key once and stores it:

{
"inputs": [{ "type": "promptString", "id": "xaalis-key", "description": "Xaalis API key", "password": true }],
"servers": {
"xaalis": { "type": "http", "url": "https://mcp.xaalis.org/mcp", "headers": { "Authorization": "Bearer ${input:xaalis-key}" } }
}
}

~/.codex/config.toml:

[mcp_servers.xaalis]
url = "https://mcp.xaalis.org/mcp"
bearer_token_env_var = "XAALIS_API_KEY"
# or local:
# [mcp_servers.xaalis]
# command = "npx"
# args = ["-y", "@xaalis/mcp"]
# env_vars = ["XAALIS_API_KEY"]

~/.gemini/settings.json or .gemini/settings.json:

{
"mcpServers": {
"xaalis": { "httpUrl": "https://mcp.xaalis.org/mcp", "headers": { "Authorization": "Bearer $XAALIS_API_KEY" } }
}
}

~/.config/devin/mcp_config.json (older Windsurf: ~/.codeium/windsurf/mcp_config.json):

{
"mcpServers": {
"xaalis": { "serverUrl": "https://mcp.xaalis.org/mcp", "headers": { "Authorization": "Bearer ${env:XAALIS_API_KEY}" } }
}
}

settings.json:

{
"context_servers": {
"xaalis": { "command": "npx", "args": ["-y", "@xaalis/mcp"], "env": { "XAALIS_API_KEY": "sk_test_…" } }
}
}

Responses API — OpenAI calls the tools itself:

await openai.responses.create({
model: "gpt-5",
input: "Create a 15000 F CFA payment for 'Tissus wax' and give me the link.",
tools: [{
type: "mcp",
server_label: "xaalis",
server_url: "https://mcp.xaalis.org/mcp",
headers: { Authorization: `Bearer ${process.env.XAALIS_API_KEY}` },
require_approval: "always", // keep "always" with live keys
}],
});

Agents SDK: new MCPServerStreamableHttp({ url: "https://mcp.xaalis.org/mcp", requestInit: { headers: { Authorization: … } } }) (TypeScript) or MCPServerStreamableHttp(params={"url": …, "headers": {…}}) (Python).

MCP connector (beta header mcp-client-2025-11-20):

{
"mcp_servers": [{ "type": "url", "url": "https://mcp.xaalis.org/mcp", "name": "xaalis", "authorization_token": "sk_test_…" }],
"tools": [{ "type": "mcp_toolset", "mcp_server_name": "xaalis" }]
}

Complete, runnable versions of these: integrations/ai/examples/ in the Xaalis repository.

Two Agent Skills, in the Claude Code plugin and usable by any skills-aware agent:

  • xaalis-integration — add Xaalis to an app: server-side payment creation, redirect, webhook verification (Node, Python, PHP, Go), fulfilment, sandbox tests, refunds, subscriptions, payouts, go-live.
  • xaalis-operations — run a business through the MCP tools: collect and confirm, refund, subscriptions, balance, webhook debugging, agent-wallet payouts, error handling.

For agents that read AGENTS.md (Codex, Gemini CLI, Copilot, Jules…), paste the ready-made section integrations/ai/AGENTS.xaalis.md into yours. Cursor: integrations/ai/cursor/xaalis.mdc → .cursor/rules/.

The same tool catalog runs in-process: you pass the tool definitions to your model and execute its calls.

TypeScript — @xaalis/ai-tools:

import { AGENT_RULES, XaalisToolkit } from "@xaalis/ai-tools";
import { openAITools, runOpenAIToolCall } from "@xaalis/ai-tools/openai"; // Responses / Chat Completions
import { anthropicTools, runAnthropicToolUse } from "@xaalis/ai-tools/anthropic";
import { vercelTools } from "@xaalis/ai-tools/vercel"; // AI SDK: tools: vercelTools(kit)
import { langChainTools } from "@xaalis/ai-tools/langchain"; // needs @langchain/core
const kit = new XaalisToolkit({ apiKey: process.env.XAALIS_API_KEY }); // no key: docs + sandbox signup
// restricted key (rk_) or OAuth token: const kit = await XaalisToolkit.connect({ apiKey }) — loads its scopes
const tools = openAITools(kit); // pass to the model
const output = await runOpenAIToolCall(kit, call.name, call.arguments); // run what it calls

Python — xaalis.ai (standard library only):

from xaalis.ai import AGENT_RULES, XaalisToolkit
kit = XaalisToolkit(os.environ.get("XAALIS_API_KEY"), allow_live_refunds=False)
tools = kit.openai_tools() # or openai_chat_tools(), anthropic_tools(), langchain_tools()
output = kit.run_for_model(call.name, call.arguments)

Results are JSON; errors come back as {"error": {"code", "message", "hint", "outcome_unknown"}} so the model knows the next step. After a sandbox signup, rebuild the tool list (kit.tools() changes).

Keys column: sk = merchant keys (and restricted keys / OAuth with the matching scope), ak = agent-wallet keys.

Tool Keys Does
xaalis_whoami all connected key, mode, account/wallet, available tools
xaalis_search_docs all search this documentation
xaalis_sandbox_signup none create a sandbox account (email, business name)
xaalis_create_payment · _get_payment · _list_payments sk payment + checkout_url; status
xaalis_simulate_payment sk_test make a test payment succeed or fail
xaalis_refund_payment · _list_refunds sk (live: if allowed) full refund of a Wave payment; check it
xaalis_get_balance sk available and reserved XOF
xaalis_create_payout sk_test payout from the merchant balance (sandbox)
xaalis_get_payout · _list_payouts sk payout status
xaalis_list_webhook_deliveries sk recent webhooks, attempts, last error
xaalis_create_subscription · _get_subscription · _list_subscriptions · _cancel_subscription sk subscriptions and instalment plans
xaalis_advance_subscription sk_test jump to the next billing event
xaalis_get_invoice · _list_invoices sk invoices and their stable payment link
xaalis_create_agent_wallet · _fund_agent_wallet · _reclaim_agent_wallet · _issue_agent_key sk_test set up an agent wallet (production: a human, in the dashboard)
xaalis_disable_agent_wallet · _list_agent_wallets · _get_agent_wallet sk stop and inspect agent wallets
xaalis_agent_get_wallet · _agent_pay · _agent_get_payout · _agent_list_payouts ak the agent’s own wallet and payouts

Resources: xaalis://rules, xaalis://docs/llms.txt, xaalis://docs/llms-full.txt, xaalis://openapi.json. Prompts: accept_payment, integrate_xaalis, sandbox_tour.

  • The hosted server keeps nothing: a request with a key or token is handled and forgotten; an anonymous /sandbox session holds only a sandbox key, in memory. Keys, tokens and request bodies are never logged.
  • OAuth tokens last five minutes (clients refresh them). The server checks their signature and audience, and the API re-checks consent, membership and scopes on every call — a withdrawn consent takes effect at once.
  • A live key is only ever sent over HTTPS.
  • Give an agent the least it needs: a sandbox key to build and test; for live, a live key (money in) and, if it must pay people, its own agent wallet with a small balance and cap. Disable the wallet to stop it instantly.
  • Treat anything the agent reads (web pages, emails, documents) as untrusted: it can’t unlock tools its key doesn’t have, but review what it proposes before approving live actions.