---
title: "Build with AI"
description: "Build with AI on Flowie Exchange. Give AI agents native access to Peppol e-invoicing — MCP servers for Claude, Cursor and custom agents, agent-ready docs (llms.txt), and self-service agent onboarding."
canonical: "https://docs.get-flowie.com/build-with-ai/"
source: "https://docs.get-flowie.com/build-with-ai/index.html"
---

# Build with AI

AI Agents

# 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](<#mcp>), the [agent-ready docs](<#docs-for-agents>), and [self-service agent onboarding](<#agent-onboarding>).

Same auth, same quota, same sandbox

Every AI surface is a thin layer over the REST API you already know. MCP tool calls are forwarded to the underlying FastAPI handler with your `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. ](<#mcp>) ### [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. ](<#docs-for-agents>) ### [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. ](<agent-onboarding.html>)

## 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 eight tags an agent actually needs: `Documents`, `Directory`, `Companies`, `Lifecycle`, `Compliance`, `Partners`, `UBL Generator`, `Portability`. 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.
[code] 
    Authorization: Bearer flw_test_your_key_here
[/code]

Use a `flw_test_…` key against the sandbox host while you're developing the agent — every test recipient from the [sandbox guide](<../sandbox/index.html>) is reachable through MCP exactly as it is through REST. Need a key? [Bootstrap one in one click](<../index.html#get-test-key>), or — if the agent must **request its own key on behalf of a real user** — see the [OAuth consent flow](<agent-onboarding.html#oauth>).

### Quickstart — Claude Desktop

Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
[code] 
    {
      "mcpServers": {
        "flowie-exchange": {
          "url": "https://back.flowie.ink/exchange/mcp",
          "transport": "streamable-http",
          "headers": {
            "Authorization": "Bearer flw_test_your_key_here"
          }
        }
      }
    }
[/code]

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):
[code] 
    {
      "mcpServers": {
        "flowie-exchange": {
          "url": "https://back.flowie.ink/exchange/mcp",
          "transport": "streamable-http",
          "headers": { "Authorization": "Bearer flw_test_your_key_here" }
        }
      }
    }
[/code]

Or register globally so every project sees it:
[code] 
    claude mcp add flowie-exchange https://back.flowie.ink/exchange/mcp \
      --transport streamable-http \
      --header "Authorization: Bearer flw_test_your_key_here"
[/code]

### 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:
[code] 
    # 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())
[/code]

### Tool catalog (curated)

The curated server exposes one MCP tool per FastAPI operation tagged `Documents`, `Directory`, `Companies`, `Lifecycle`, `Compliance`, `Partners`, `UBL Generator`, `Portability`. The high-leverage ones for agents:

Tool| What it does  
---|---  
`send_document`| Send an e-invoice / credit note / order over Peppol.  
`resolve_portability_taxpayer`| One identifier → the company's identity, its regime and what its platform change requires.  
`open_portability_request`| Open a platform change: designation agreement, computed clocks, first evidence entry.  
`record_portability_event`| Record a notice, an objection (classified), an agreement or the annuaire update.  
`get_portability_request`| State re-derived from the evidence chain, with tacit approval and chain verification.  
`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.  
`list_business_terms`| Every EN 16931 business term with its French obligation — what a BT id means, and whether the reform requires it.  
  
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](<../reference/index.html>) for the canonical shape.

### Common workflow — _"What invoices arrived this week?"_

The agent picks the right tools from the prompt; you do nothing.
[code] 
    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
[/code]

### Common workflow — _"Send an invoice to ACME"_

Three tools, one chain. The agent verifies the recipient before sending.
[code] 
    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
               }]
             }
           })
[/code]

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"_
[code] 
    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"
           })
[/code]

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](<../reference/webhooks.html#events>) for confirmation. Belgian invoices skip this step (HERMES was decommissioned 2025-12-31).

### Common workflow — _"Onboard a new supplier"_
[code] 
    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
[/code]

### Direct HTTP (no SDK)

MCP is just JSON-RPC over an HTTP POST. If you don't want the SDK:
[code] 
    # 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}
        }
      }'
[/code]

### 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](<../reference/errors.html>) 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/full` or rename.
  * **`invalid arguments`** — input schema mismatch. Run `tools/list` and follow the `inputSchema` exactly.



### 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](<../sandbox/index.html>) for the full menu.

Tip — keep a sandbox profile in Claude Desktop

Claude Desktop supports multiple `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](<https://llmstxt.org>) 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`](<../llms.txt>)| Page index with titles and one-line descriptions — a fast lookup so an agent can decide what to fetch.  
[`llms-full.txt`](<../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`](<../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](<agent-onboarding.html>) 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](<agent-onboarding.html>).
  * **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](<agent-onboarding.html#oauth>).
