---
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

Flowie publishes **two Model Context Protocol servers** , each on production and on staging. Connect one to Claude, ChatGPT, Cursor, VS Code or Claude Code and sign in with your normal Flowie login (SSO and Google included): no API key, nothing to request from Flowie first.

Copy-ready setup, one page

Everything in this section, as a single Markdown page you can paste into an assistant: [`https://docs.get-flowie.com/mcp.md`](<../mcp.md>). 

### Which server do I want?

  * **App** (`/agent-hub/mcp`) — **what most people want** : use the Flowie app through an LLM (Claude, ChatGPT, Cursor…). Purchase requests, approvals, tasks, budgets, flows, forms, partners, payments, documents. It acts as the signed-in user, with exactly their permissions. Sign-in only.
  * **Exchange API** (`/exchange/mcp`) — **for integrations** : a system talking to Flowie (ERP, scripts, backends, automated pipelines). Send, receive, validate and track e-invoices, companies, partners, directory. Typically with an API key; sign-in works too.



You can register both in the same client. They do not share credentials: an API key works only on the Exchange API server, and the App server accepts only a sign-in. `back.p2p-flowie.com` is production; `back.flowie.ink` is staging.

**Volume decides too.** The App server works at a person's pace: **60 requests a minute per user** , one object per call; over it, the `429` names this server as the way out. The Exchange API server carries the volume: an API key's budget runs from 120 to 2,400 requests a minute by plan (see [Rate limits & quotas](<#rate-limits>)), `send_documents_batch` sends many documents in one call, and each server's `instructions` names the other, so an agent that connected to the wrong one is told where to go.

**Creating a document** is one call on either server, and the two speak the same vocabulary. On the Exchange API server, `send_document` with `type`, `from`, `to` and a `document` carrying `number`, `issueDate`, `currency` and `lines` (`description`, `quantity`, `unitPrice`, `vatRate` as a percentage) creates the document, computes its totals and sends it; an `Idempotency-Key` makes a retry safe ([reference](<../reference/index.html#send-document>)). On the App server, `create_transaction_document` with `documentType`, `number`, `issuedAt`, the other party (`buyerId` when you sell, `sellerId` when you buy) and `lineItems` (`quantity`, `unitPrice`, `taxRate` as a percentage) creates it in the Flowie app, totals computed, without sending it anywhere.

### Endpoints

Server| What it exposes| Authentication| Production| Sandbox / staging  
---|---|---|---|---  
**App** — most people want this one | The Flowie app as tools: what Flowie's in-app AI agent can do, acting as the signed-in user | Sign-in only — no API key | `https://back.p2p-flowie.com/agent-hub/mcp` | `https://back.flowie.ink/agent-hub/mcp`  
**Exchange API** — for integrations | Every documented operation of the Exchange API (e-invoicing, companies, partners, directory) | Sign-in, `flw_*` API key or user JWT | `https://back.p2p-flowie.com/exchange/mcp` | `https://back.flowie.ink/exchange/mcp`  
  
`…/exchange/mcp/full` still works: it is an alias of the Exchange API server, kept so existing configurations keep running. Use `/exchange/mcp` for new setups.

On the App server, `list_my_organizations` lists the organizations you can reach, every tool takes an optional `organization_id`, and `search_flowie_api` / `call_flowie_api` reach any other platform operation. The Exchange API server exposes one tool per documented operation. No tool count is printed here on purpose: the sets follow the API as it grows. Your client shows the live set, and `tools/list` returns it.

Transport is **Streamable HTTP**. The legacy SSE transport is no longer mounted.

### Quickstart — Claude Code

Production, App server:
[code] 
    claude mcp add --transport http flowie-app https://back.p2p-flowie.com/agent-hub/mcp
[/code]

Then run `/mcp` in Claude Code, pick **flowie-app** and choose **Authenticate**. A browser opens on the Flowie sign-in page. To add the Exchange API server as well:
[code] 
    claude mcp add --transport http flowie-api https://back.p2p-flowie.com/exchange/mcp
[/code]

Per project, commit a `.mcp.json` instead:
[code] 
    {
      "mcpServers": {
        "flowie-app": {
          "type": "http",
          "url": "https://back.p2p-flowie.com/agent-hub/mcp"
        }
      }
    }
[/code]

### Quickstart — Claude.ai and Claude Desktop

**Settings → Connectors → Add custom connector** , paste the URL, then **Connect** and sign in. No client ID, no secret.
[code] 
    https://back.p2p-flowie.com/agent-hub/mcp
[/code]

ChatGPT works the same way: add a custom connector (developer mode) with this URL and OAuth authentication.

### Quickstart — Cursor / VS Code

**Cursor** — `~/.cursor/mcp.json` or `.cursor/mcp.json`, then click **Connect** next to the server:
[code] 
    {
      "mcpServers": {
        "flowie-app": {
          "url": "https://back.p2p-flowie.com/agent-hub/mcp"
        }
      }
    }
[/code]

**VS Code** — `.vscode/mcp.json`. VS Code uses `"servers"` and `"type": "http"`:
[code] 
    {
      "servers": {
        "flowie-app": {
          "type": "http",
          "url": "https://back.p2p-flowie.com/agent-hub/mcp"
        }
      }
    }
[/code]

### Staging / sandbox

Same commands on the staging host, signed in with a staging account:
[code] 
    claude mcp add --transport http flowie-app-staging https://back.flowie.ink/agent-hub/mcp
    claude mcp add --transport http flowie-api-staging https://back.flowie.ink/exchange/mcp
[/code]

### Authentication

Two ways in. Pick by _who is acting_ , not by which client you use.

Method| Use it when| What you configure  
---|---|---  
**Sign in** (OAuth 2.1 + PKCE) | A person is behind the agent — Claude, ChatGPT, VS Code, Cursor, Claude Code, any interactive client. Both servers. | **Nothing.** Just the server URL. The client opens the Flowie sign-in page the first time.  
**API key** (`flw_live_…` / `flw_test_…`) | No person is present — an ERP, CI, a cron, a back-end service. | An `Authorization: Bearer` header. Exchange API server only.  
  
Sign-in follows the standard MCP authorization flow. An unauthenticated call returns `401` with `WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource/mcp"`; that metadata lists `authorization_servers: ["https://<host>/exchange"]`, whose metadata (`<host>/exchange/.well-known/oauth-authorization-server`) gives the authorize endpoint `<host>/exchange/oauth/authorize`, the token endpoint `<host>/exchange/v1/oauth/token` and the registration endpoint `<host>/exchange/v1/oauth/register`. **Dynamic client registration is supported** ([RFC 7591](<https://www.rfc-editor.org/rfc/rfc7591>), public client, PKCE `S256`), and a redirect back to your own machine is accepted on any port. The sign-in page is the normal Flowie login, so SSO and Google work. The access token lasts 24 hours and the client renews it with a refresh token, without a new consent.

The token is bound to _your_ Flowie account: it reaches the organizations you can reach, with the permissions you hold in each one. An agent cannot do anything you could not do yourself.
[code] 
    claude mcp add --transport http flowie-api https://back.p2p-flowie.com/exchange/mcp \
      --header "Authorization: Bearer flw_live_..."
[/code]

That is the API-key route (production key on the production host; a `flw_test_…` key on the staging host reaches every test recipient from the [sandbox guide](<../sandbox/index.html>) — [bootstrap one in one click](<../index.html#get-test-key>)). Full details: [auth.md](<../auth.md>).

### 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 (Exchange API server)

The Exchange API server exposes one MCP tool per documented operation. 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`** — the tool name does not exist on this server. Run `tools/list` for the exact names. The App tools (workflows, tasks, purchase requests, budgets…) are on `/agent-hub/mcp`, not on `/exchange/mcp`.
  * **`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`.

**App server:** 600 JSON-RPC requests per minute per user on `/agent-hub/mcp` — the same budget as a user calling the Exchange API with their own token. Over it, the answer is `429` with `Retry-After`.

### 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."_

### Troubleshooting

  * **`401` — "Unauthorized: sign in to Flowie to use these tools."** The client has not completed sign-in. In Claude Code run `/mcp`, pick the server, **Authenticate** ; elsewhere click **Connect** on the server.
  * **"Server not found" from`claude.ai/api/…/mcp/start-auth/mcpsrv_…`** — the claude.ai connector was removed or re-added while Claude Code was running. Restart Claude Code, or add the server directly with `claude mcp add --transport http flowie-app https://back.p2p-flowie.com/agent-hub/mcp`.
  * **An API key is rejected on`/agent-hub/mcp`** — expected: the App server is sign-in only. Use `/exchange/mcp` for keys.
  * **Key rejected on the other host** — `flw_live_…` keys work on `back.p2p-flowie.com`, `flw_test_…` keys on `back.flowie.ink`.



## 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>).
