Build with AI
Flowie Exchange is built to be driven by AI. Point Claude Desktop, Claude Code, Cursor, n8n, or your own custom agent at the API and it can send, receive, and manage Peppol e-invoices as native tool calls — no glue code, no bespoke wrappers. This page is the hub for every AI surface: the MCP servers, the agent-ready docs, and self-service agent onboarding.
Authorization header preserved — so JWT, flw_* keys, tenant scoping, rate limits, and sandbox simulators all work identically.
AI tools
Three ways to put Flowie Exchange in front of an agent. Most integrations start with the MCP server.
MCP server →
Connect Claude Desktop, Claude Code, Cursor, or a custom Python agent over the Model Context Protocol and call the API as native tools.
Docs for agents →
Machine-readable docs — llms.txt as a fast page index, llms-full.txt as the whole corpus, plus one Markdown slice per endpoint.
Agent onboarding →
Let an agent self-provision: zero-friction sandbox bootstrap (no human in the loop) or OAuth-style consent with PKCE for production scope grants.
MCP server
The Flowie Exchange API ships two Model Context Protocol servers so AI agents — Claude Desktop, Claude Code, Cursor, n8n, custom Python agents — can send, receive, and manage Peppol e-invoices as native tool calls.
Endpoints
| Mode | Tools | Production | Sandbox |
|---|---|---|---|
| Curated (recommended) | 34 | https://back.p2p-flowie.com/exchange/mcp |
https://back.flowie.ink/exchange/mcp |
| Full | 94 | https://back.p2p-flowie.com/exchange/mcp/full |
https://back.flowie.ink/exchange/mcp/full |
The curated server exposes only the six tags an agent actually needs: Documents, Directory, Companies, Lifecycle, Compliance, Partners. Admin, sandbox control plane, AFNOR certification, and debug routes are hidden — fewer tokens spent on tool discovery, far fewer "wrong tool" misfires. Pick full only when the agent genuinely needs platform / white-label / certification surface.
Transport is streamable-HTTP (the modern MCP transport, MCP spec 2025-06-18). The legacy SSE transport is no longer mounted.
Authentication
Every request the agent makes is forwarded to the FastAPI handler with the original Authorization header preserved, so the same scoping rules apply: tenant isolation, per-key quotas, sandbox vs live partitioning.
Authorization: Bearer flw_test_your_key_here
Use a flw_test_… key against the sandbox host while you're developing the agent — every test recipient from the sandbox guide is reachable through MCP exactly as it is through REST. Need a key? Bootstrap one in one click, or — if the agent must request its own key on behalf of a real user — see the OAuth consent flow.
Quickstart — Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"flowie-exchange": {
"url": "https://back.flowie.ink/exchange/mcp",
"transport": "streamable-http",
"headers": {
"Authorization": "Bearer flw_test_your_key_here"
}
}
}
}
Restart Claude Desktop. The hammer icon shows 34 tools loaded. Try: "List my last 5 incoming invoices."
Quickstart — Claude Code
In the project directory, drop a .mcp.json file (Claude Code picks it up automatically per project):
{
"mcpServers": {
"flowie-exchange": {
"url": "https://back.flowie.ink/exchange/mcp",
"transport": "streamable-http",
"headers": { "Authorization": "Bearer flw_test_your_key_here" }
}
}
}
Or register globally so every project sees it:
claude mcp add flowie-exchange https://back.flowie.ink/exchange/mcp \
--transport streamable-http \
--header "Authorization: Bearer flw_test_your_key_here"
Quickstart — Cursor / VS Code
In Cursor: Settings → MCP → Add new server, paste the same JSON shape as Claude Desktop. In VS Code with the Continue extension: same JSON under continue.config.mcpServers. Both speak streamable-HTTP natively.
Quickstart — Python (mcp SDK)
For custom agents, the official mcp Python SDK speaks streamable-HTTP directly:
# pip install mcp
import asyncio, os
from mcp.client.streamable_http import streamablehttp_client
from mcp import ClientSession
URL = "https://back.flowie.ink/exchange/mcp"
KEY = os.environ["FLOWIE_KEY"]
async def main():
async with streamablehttp_client(
URL, headers={"Authorization": f"Bearer {KEY}"}
) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
print(f"{len(tools.tools)} tools available")
# Call a tool by name with REST-style args
result = await session.call_tool(
"list_documents",
arguments={"direction": "incoming", "status": "unread", "limit": 5},
)
print(result.content[0].text)
asyncio.run(main())
Tool catalog (curated)
The curated server exposes one MCP tool per FastAPI operation tagged Documents, Directory, Companies, Lifecycle, Compliance, or Partners. The high-leverage ones for agents:
| Tool | What it does |
|---|---|
send_document | Send an e-invoice / credit note / order over Peppol. |
list_documents | Filter by direction, status, type, date range. |
search_documents | Full-text + structured search across all documents. |
get_document_structured | Flat, agent-friendly view — every field as a primitive. |
validate_document | Pre-flight a payload through BIS / EN-16931 rules. |
update_lifecycle | Approve, reject, mark as paid, dispute. |
search_directory | Find Peppol participants by name, VAT, or country. |
verify_recipient | Check a Peppol ID can receive a given document type. |
resolve_company | Look up by VAT / SIREN — get Peppol ID + enriched profile. |
create_company | Register a sender, auto-publish to the Peppol SMP. |
get_compliance_report | Latest PPF (FR) or SDI (IT) report status for a document. |
Run tools/list over MCP to enumerate the full set with input schemas and descriptions. Every tool's input schema mirrors the REST endpoint's request body — see the API Reference for the canonical shape.
Common workflow — "What invoices arrived this week?"
The agent picks the right tools from the prompt; you do nothing.
User: "What invoices arrived this week and which ones are still unpaid?"
Agent → list_documents({direction: "incoming", since: "2026-04-26"})
→ for each: get_document_structured({documentId})
→ for each unpaid: get_compliance_report({documentId})
→ summarises totals by supplier, flags the ones past dueDate
Common workflow — "Send an invoice to ACME"
Three tools, one chain. The agent verifies the recipient before sending.
User: "Bill ACME BVBA €4,500 + VAT for April consulting, due in 30 days."
Agent → search_directory({q: "ACME BVBA"}) # finds peppolId
→ verify_recipient({peppolId, documentType: "INVOICE"})
→ send_document({
type: "invoice",
from: "comp_abc123",
to: "0208:0123456789",
document: {
number: "INV-2026-0451",
issueDate: "2026-04-30",
dueDate: "2026-05-30",
currency: "EUR",
lines: [{
description: "Consulting — April 2026",
quantity: 1, unit: "lot",
unitPrice: 4500.00, vatRate: 21
}]
}
})
The agent sees the returned documentId + deliveryStatus and reports back. Pass an Idempotency-Key at the REST layer if you want retry safety — MCP forwards it as a tool argument.
Common workflow — "Mark INV-0417 as paid"
User: "INV-2026-0417 was paid yesterday — close the loop."
Agent → search_documents({number: "INV-2026-0417"}) # → documentId
→ update_lifecycle({
documentId,
status: "paid",
note: "Paid 2026-04-29 via SEPA"
})
The lifecycle change automatically triggers PPF (FR) or SDI (IT) reporting where applicable — the agent doesn't need to know about that. Watch compliance.reported on your webhook stream for confirmation. Belgian invoices skip this step (HERMES was decommissioned 2025-12-31).
Common workflow — "Onboard a new supplier"
User: "Add Globex SRL (VAT IT09876543210) as a partner and check they're on Peppol."
Agent → resolve_company({vatNumber: "IT09876543210"}) # enriched profile
→ verify_recipient({peppolId}) # canReceive: true?
→ save_partner({...}) # in your CRM/ERP
Direct HTTP (no SDK)
MCP is just JSON-RPC over an HTTP POST. If you don't want the SDK:
# 1. Initialize the session
curl -X POST https://back.flowie.ink/exchange/mcp \
-H "Authorization: Bearer $FLOWIE_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {"name": "curl", "version": "1.0"}
}
}'
# 2. List tools
curl -X POST https://back.flowie.ink/exchange/mcp \
-H "Authorization: Bearer $FLOWIE_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# 3. Call a tool
curl -X POST https://back.flowie.ink/exchange/mcp \
-H "Authorization: Bearer $FLOWIE_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{
"name":"list_documents",
"arguments":{"direction":"incoming","limit":5}
}
}'
Errors
MCP errors mirror the underlying REST errors — same codes, same shape, wrapped in JSON-RPC. A 401 from REST surfaces as MCP error -32001 with the original Flowie error code in data.errorCode. See the error catalog for everything you might see.
The two MCP-specific errors:
tool not found— agent called a tool that's not in the curated set. Switch to/mcp/fullor rename.invalid arguments— input schema mismatch. Runtools/listand follow theinputSchemaexactly.
Rate limits & quotas
MCP calls inherit your REST quota — there's no separate budget. One MCP tools/call = one REST request. Use the same X-Flowie-RateLimit-Remaining header logic to back off; the header is surfaced on the JSON-RPC response envelope under _meta.
Sandbox
Point the agent at https://back.flowie.ink/exchange/mcp with a flw_test_… key and every sandbox feature works: forced errors via X-Sandbox-Force-Error, simulated recipients (0208:SIM_HAPPY, SIM_DISPUTE, TEST_AP_FAIL), lifecycle simulators, the lot. See the sandbox guide for the full menu.
mcpServers entries. Register both flowie-exchange-sandbox (test key, sandbox URL) and flowie-exchange-prod (live key, prod URL). Then prompt the agent explicitly: "Use the sandbox server to dry-run this."
When to use full vs curated
- Curated — agents that send, receive, search, and reconcile invoices. Default choice for 95% of integrations.
- Full — IDE integrations, ops scripts, AFNOR-certified flows, white-label admin, request inspector. Larger context cost; only when you genuinely need the extra surface.
You can mount both — agents pick the right one based on the host you point them at. There's no auth difference between the two, so the same key works against both URLs.
Docs for agents
The whole documentation site is published in machine-readable form, following the llms.txt convention. Point an agent (or a RAG pipeline) at these instead of scraping HTML — every page carries a <link rel="alternate" type="text/markdown"> so tools can discover them automatically.
| Resource | What it is |
|---|---|
llms.txt | Page index with titles and one-line descriptions — a fast lookup so an agent can decide what to fetch. |
llms-full.txt | The entire corpus in one file — every page back-to-back as clean Markdown. Drop it straight into a context window. |
llms/reference/index.md | Directory of per-endpoint Markdown slices — one file per API operation, so an agent can pull just the one endpoint it needs. |
openapi.json | The full OpenAPI 3.1 spec — the same one that generates the MCP tool schemas. |
Everything under docs.get-flowie.com is reachable this way: https://docs.get-flowie.com/llms.txt, https://docs.get-flowie.com/llms-full.txt, and one Markdown file per endpoint under https://docs.get-flowie.com/llms/reference/.
Agent onboarding
An agent doesn't need a human to hand it a key. Two self-service paths let it provision access on its own — see the full agent onboarding guide for both.
- Sandbox bootstrap — one unauthenticated POST returns a 7-day
flw_test_…key plus a starter sandbox company. Zero human in the loop; ideal for prototyping, demos, and agent CI. See the bootstrap flow. - OAuth consent (PKCE) — when the agent must act on behalf of a real user, the OAuth-style consent flow issues a scoped, production-grade key after the user approves. See the OAuth consent flow.