{
  "openapi": "3.1.0",
  "info": {
    "title": "Flowie Exchange API",
    "description": "\n## Flowie Exchange API\n\n**The Flowie Exchange API for every persona** — from a solo freelancer to a white-label ISV managing 10,000 companies.\n\nDesign principle: **Stripe Connect for Peppol**. Simple for the simple case, powerful for the complex one.\n\n### Worldwide Coverage\n\nFlowie covers **47 countries** across four continents — Europe (EU-27, EEA, UK, Switzerland),\nthe Middle East (KSA, UAE, Israel, Egypt, Türkiye), Asia (India, Singapore, Malaysia, Thailand,\nVietnam, Japan, South Korea, China), and the Pacific (Australia, New Zealand). The API auto-\ndetects the country from the identifier scheme and enriches data from national registries.\n\n### 4 Personas, 1 API\n\n| Persona | What they need | Example |\n|---------|----------------|---------|\n| **Client** | Send/receive invoices | Accountant using Flowie dashboard |\n| **Agent** | Structured data, batch ops, idempotency | AI workflow, n8n, Make.com |\n| **Integrator** | Connect their app to Peppol for their users | Odoo plugin, WinBooks connector |\n| **White-label** | Run their own branded Peppol service | Accounting firm offering Peppol |\n\n---\n\n### Authentication\n\nAll requests require a Bearer token in the `Authorization` header. **Two authentication methods** are supported — use whichever fits your use case:\n\n#### Method 1: Flowie JWT Token (existing users)\n\nIf you already use the Flowie platform, use your existing JWT token. No extra setup needed.\n\n```\nAuthorization: Bearer eyJhbGciOiJSUzI1NiIs...\n```\n\n- Issued by Flowie's Auth0 tenant\n- Organization resolved from the `_permissions` claim in the token\n- Full access (`*` scope) — permissions are managed at the organization level\n- **Best for**: Dashboard users, existing Flowie apps, internal services\n\n#### Method 2: Exchange API Key (external consumers)\n\nFor programmatic access, generate an API key from the Platform endpoints.\n\n```\nAuthorization: Bearer flw_live_a1b2c3d4e5f6...\n```\n\n**Key types:**\n\n| Type | Prefix | Scope | Use case |\n|------|--------|-------|----------|\n| **Personal** | `flw_live_` | Single company | Client, Agent |\n| **Platform** | `flw_plat_live_` | All managed companies | Integrator |\n| **White-label** | `flw_wl_live_` | Branded instance | White-label partner |\n\n**Scoped permissions** (API keys only):\n\n| Scope | Allows |\n|-------|--------|\n| `send` | Send documents |\n| `receive` | Configure receiving (webhooks, SMP) |\n| `documents.read` | Read documents, download XML/PDF |\n| `documents.search` | Search documents |\n| `documents.write` | Mark read, archive, tag, add notes |\n| `companies.read` | Read company details |\n| `companies.write` | Update company details |\n| `directory` | Search directory, verify recipients |\n| `partners` | Manage trading partners |\n| `payments` | Manage payment methods, terms, and partner sharing |\n| `lifecycle` | Update document lifecycle status |\n| `compliance` | View compliance dashboard and reports |\n| `stats` | Read usage statistics |\n| `platform` | Manage platform (onboard, keys, settings) |\n| `*` | All scopes (default for personal keys) |\n\n**Sandbox**: Use `flw_test_` prefix keys — same endpoints, no real Peppol delivery.\n\nPlatform keys use the `X-Flowie-Company` header to act on behalf of a managed company.\n\n#### How it works\n\nBoth methods return the same result to the API — the caller is identified by their organization ID,\nand endpoints behave identically regardless of which auth method is used.\n\n```\nAuthorization: Bearer <token>\n                      │\n                      ├─ starts with flw_ → API Key (database lookup)\n                      │\n                      └─ otherwise → JWT (Auth0 JWKS verification)\n```\n\n---\n\n### Built-in Compliance\n\nFlowie auto-reports lifecycle changes to government platforms and handles hard\nclearance across **47 jurisdictions** worldwide. Highlights:\n\n**Europe**\n- **France**: PPF (Portail Public de Facturation), Flowie is registered Plateforme Agréée (PA, formerly PDP) number 0040 — mandate Sept 2026\n- **Italy**: SDI (Sistema di Interscambio) — mandatory since 2019\n- **Belgium**: Peppol BIS — B2B mandate live since 1 January 2026 (HERMES decommissioned 2025-12-31)\n- **Germany**: XRechnung / ZUGFeRD — phased B2B 2025–2028 (Wachstumschancengesetz)\n- **Spain**: Veri*Factu + Crea y Crece B2B mandate phasing\n- **Poland**: KSeF mandatory clearance — large taxpayers Feb 2026, all April 2026\n- **Romania**: RO e-Factura mandatory clearance, universal B2B since July 2024\n- **Hungary**: NAV Online Számla 3.0 — universal real-time reporting\n- **Croatia**: Fiscalisation 2.0 — B2B mandate live since January 2026\n\n**Middle East / Africa**\n- **Saudi Arabia**: ZATCA Fatoora clearance, Wave 24 (full register) by 30 June 2026\n- **UAE**: Peppol 5-corner with FTA Data Reporting Platform — Phase 1 large taxpayers from 1 July 2026\n- **Israel**: ITA SHAAM clearance — threshold drops to NIS 5,000 from June 2026\n- **Egypt**: ETA e-invoicing universal clearance + e-receipt for B2C\n- **Türkiye**: GİB e-Fatura + e-Arşiv, universal from January 2026\n\n**Asia / Pacific**\n- **India**: GST IRP-issued IRN — universal above ₹5 cr turnover, 30-day reporting cap above ₹10 cr\n- **Singapore**: Peppol InvoiceNow + GST 5-corner with IRAS — phased through 2031\n- **Malaysia**: LHDN MyInvois clearance — final wave 1 January 2026 (RM 1m floor)\n- **Australia**: Peppol PINT A-NZ via ATO — federal B2G default by Dec 2026\n- **New Zealand**: Peppol PINT A-NZ via MBIE — supplier mandate Jan 2027 (revenue > NZ$33m)\n- **Japan**: Peppol JP PINT + Qualified Invoice System\n- **South Korea**: NTS HomeTax e-Tax invoice — universal corporate clearance since 2011\n- **China**: Fully Digitalized e-fapiao + Golden Tax IV — codified by 2026 VAT Law\n- **Vietnam**: GDT mandatory e-invoice + Decree 70/2025 expansion\n- **Thailand**: Voluntary e-Tax Invoice / e-Receipt\n\nSee `docs/compliance/index.html` for the full coverage map across all 47 countries.\n\n### AFNOR XP Z12-013\n\nEndpoints under `/afnor/` implement the French AFNOR certification standard for PA / PDP interoperability.\nSame backend, different contract — use these for French e-invoicing certification compliance.\n\n### Idempotency\n\nAll `POST` endpoints accept an `Idempotency-Key` header. Same key within 24 hours returns the cached response.\n\n### Pagination\n\nAll list endpoints use cursor-based pagination: `?limit=50&cursor=xxx`\n\n### Rate Limiting\n\nStandard headers on every response: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`.\n\n| Tier | Requests/min |\n|------|-------------|\n| Free | 60 |\n| Starter | 120 |\n| Pro | 300 |\n| Platform | 600 |\n| White-label | 1,200 |\n",
    "version": "3.0.0"
  },
  "paths": {
    "/health/liveness": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Liveness probe — is the process up?",
        "description": "Trivial liveness probe used by Kubernetes / Cloud Run / load balancers.\n\nReturns immediately without touching any upstream — the only thing a 200\nhere proves is that the FastAPI event loop is still responsive. Never\nreturns non-2xx unless the process is wedged at the network layer.\n\n**Example response (200):**\n```json\n{\"status\": \"ok\"}\n```\n\n**Errors**\n\n| Status | Code | When                                                 |\n|--------|------|------------------------------------------------------|\n| —      | —    | This endpoint does not emit error envelopes.         |",
        "operationId": "liveness_health_liveness_get",
        "responses": {
          "200": {
            "description": "Process is up and the HTTP loop is responsive.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Liveness Health Liveness Get"
                },
                "example": {
                  "status": "ok"
                }
              }
            }
          }
        }
      }
    },
    "/health/readiness": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Readiness probe — should traffic be sent here?",
        "description": "Readiness probe used by orchestrators to decide whether to route traffic.\n\nInspects the in-process circuit breaker for every tracked upstream\ndependency (documents, org-v2, …). If any circuit is **open** the body\nreports ``status=degraded`` and the caller (e.g. Kubernetes) should pull\nthe pod out of rotation until the circuit closes again.\n\n**Example response (200 — all closed):**\n```json\n{\n  \"status\": \"ok\",\n  \"circuits\": {\n    \"documents\": {\"state\": \"closed\", \"failures\": 0, \"cooldown_remaining\": 0},\n    \"org-v2\":    {\"state\": \"closed\", \"failures\": 0, \"cooldown_remaining\": 0}\n  }\n}\n```\n\n**Example response (503 — one open):**\n```json\n{\n  \"status\": \"degraded\",\n  \"circuits\": {\n    \"documents\": {\"state\": \"closed\", \"failures\": 0, \"cooldown_remaining\": 0},\n    \"org-v2\":    {\"state\": \"open\",   \"failures\": 7, \"cooldown_remaining\": 23}\n  }\n}\n```\n\n**Errors**\n\n| Status | Code         | When                                                       |\n|--------|--------------|------------------------------------------------------------|\n| 503    | `degraded`   | One or more upstream circuits are open — pod not ready.    |",
        "operationId": "readiness_health_readiness_get",
        "responses": {
          "200": {
            "description": "All tracked upstream circuits are closed — the service is ready to take traffic.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Readiness Health Readiness Get"
                },
                "example": {
                  "status": "ok",
                  "circuits": {
                    "documents": {
                      "state": "closed",
                      "failures": 0,
                      "cooldown_remaining": 0
                    },
                    "org-v2": {
                      "state": "closed",
                      "failures": 0,
                      "cooldown_remaining": 0
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "One or more circuits are open — load balancer should stop sending traffic.",
            "content": {
              "application/json": {
                "example": {
                  "status": "degraded",
                  "circuits": {
                    "documents": {
                      "state": "closed",
                      "failures": 0,
                      "cooldown_remaining": 0
                    },
                    "org-v2": {
                      "state": "open",
                      "failures": 7,
                      "cooldown_remaining": 23
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/health/contracts": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Contract-monitor status across tracked upstream services",
        "description": "Snapshot of the background contract monitor.\n\nA separate worker pings each upstream service on a schedule and records\nthe last response time + any error. This endpoint returns the current\nsnapshot — useful for dashboards and for verifying schema drift was\ndetected. ``status=degraded`` means at least one upstream contract failed\nits last check; consult the ``services`` map for the offending entry.\n\n**Example response (200 — everything healthy):**\n```json\n{\n  \"status\": \"ok\",\n  \"services\": {\n    \"documents\": {\"status\": \"ok\", \"responseMs\": 42,\n                  \"lastCheck\": \"2026-06-17T08:30:12.512000+00:00\", \"error\": null},\n    \"org-v2\":    {\"status\": \"ok\", \"responseMs\": 58,\n                  \"lastCheck\": \"2026-06-17T08:30:12.518000+00:00\", \"error\": null}\n  }\n}\n```\n\n**Example response (503 — one upstream failing):**\n```json\n{\n  \"status\": \"degraded\",\n  \"services\": {\n    \"org-v2\": {\"status\": \"error\", \"responseMs\": 5021,\n               \"lastCheck\": \"2026-06-17T08:30:11.001000+00:00\",\n               \"error\": \"timeout after 5s\"}\n  }\n}\n```\n\n**Errors**\n\n| Status | Code         | When                                                          |\n|--------|--------------|---------------------------------------------------------------|\n| 503    | `degraded`   | At least one tracked contract failed its last health check.   |",
        "operationId": "contract_status_health_contracts_get",
        "responses": {
          "200": {
            "description": "Background contract monitor reports every tracked upstream contract as healthy.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Contract Status Health Contracts Get"
                },
                "example": {
                  "status": "ok",
                  "services": {
                    "documents": {
                      "status": "ok",
                      "responseMs": 42,
                      "lastCheck": "2026-06-17T08:30:12.512000+00:00"
                    },
                    "org-v2": {
                      "status": "ok",
                      "responseMs": 58,
                      "lastCheck": "2026-06-17T08:30:12.518000+00:00"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "At least one upstream contract is failing (schema drift, 5xx, timeout).",
            "content": {
              "application/json": {
                "example": {
                  "status": "degraded",
                  "services": {
                    "documents": {
                      "status": "ok",
                      "responseMs": 41,
                      "lastCheck": "2026-06-17T08:30:12.512000+00:00"
                    },
                    "org-v2": {
                      "status": "error",
                      "responseMs": 5021,
                      "lastCheck": "2026-06-17T08:30:11.001000+00:00",
                      "error": "timeout after 5s"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/companies": {
      "post": {
        "tags": [
          "Companies"
        ],
        "summary": "Create (or find-and-link) a company from a VAT number",
        "description": "Create a company in the caller's Flowie organization.\n\nFlowie first asks org-v2 to find-or-create an organization by `vatNumber`; if the\nupstream registry already knows the company, the returned profile is enriched and\nlinked rather than duplicated. The Peppol ID is derived from the VAT prefix (ICD\nscheme code) and the local registration row is created with `status=\"active\"` on\n`POST /{id}/register`.\n\n**Example request:**\n```http\nPOST /v1/companies\nContent-Type: application/json\n\n{\n  \"vatNumber\": \"FR86797978996\",\n  \"name\": \"Acme SAS\",\n  \"address\": {\n    \"street\": \"123 Rue de la Paix\",\n    \"city\": \"Paris\",\n    \"postalCode\": \"75001\",\n    \"country\": \"FR\"\n  }\n}\n```\n\n**Example response (201):**\n```json\n{\n  \"id\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n  \"name\": \"Acme SAS\",\n  \"country\": \"FR\",\n  \"vatNumber\": \"FR86797978996\",\n  \"peppolId\": \"0009:797978996\",\n  \"status\": \"active\"\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | VAT malformed, unsupported country prefix.                    |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `companies:write`.                                  |\n| 422    | `validation_error`     | Body failed schema validation.                                |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Org-v2 returned a non-2xx response.                           |\n| 503    | `upstream_unavailable` | Org-v2 unreachable / timed out.                               |",
        "operationId": "create_company_v1_companies_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanyCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Company created — or an existing org-v2 record matched by VAT was linked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyResponse"
                },
                "example": {
                  "id": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "organizationId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "name": "HOZELOCK EXEL",
                  "slug": "hozelock-exel",
                  "legalName": "HOZELOCK EXEL",
                  "country": "FR",
                  "vatNumber": "FR02779658772",
                  "taxNumber": "FR02779658772",
                  "registrationNumber": "77965877200024",
                  "legalAddressId": "019a6e5b-3b4c-7000-a460-a09181acc257",
                  "address": {
                    "street": "891 ROUTE DES FRENES",
                    "streetLine2": "Z.I.DE JOUX ARNAS NORD",
                    "city": "ARNAS",
                    "postalCode": "69400",
                    "country": "FR"
                  },
                  "isPublic": false,
                  "dataProviderType": "Whitepages",
                  "dataProviderSyncDate": "2025-11-10T15:21:04.068319Z",
                  "peppolId": "0009:02779658772",
                  "status": "active",
                  "smpRegistered": true,
                  "createdAt": "2025-11-10T15:21:03.581980Z",
                  "updatedAt": "2026-03-06T09:08:26.855434Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Companies"
        ],
        "summary": "List companies the caller can manage",
        "description": "List the companies the caller's API key can act on.\n\nFor JWT auth, this is every org in the user's `_permissions` claim that has a\nFlowie row; for API-key auth, it is the single org the key is bound to. Pass the\n`cursor` returned by the previous page to walk results. Set `include_address=false`\nto skip the N parallel address resolves and get a faster, lighter list.\n\n**Example request:**\n```http\nGET /v1/companies?country=FR&limit=20&include_address=true\n```\n\n**Example response (200):**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n      \"name\": \"HOZELOCK EXEL\",\n      \"country\": \"FR\",\n      \"vatNumber\": \"FR02779658772\",\n      \"peppolId\": \"0009:02779658772\",\n      \"status\": \"active\"\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | Bad cursor / unsupported filter combination.                  |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `companies:read`.                                   |\n| 422    | `validation_error`     | Query failed schema validation.                               |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Org-v2 returned a non-2xx response.                           |\n| 503    | `upstream_unavailable` | Org-v2 unreachable / timed out.                               |",
        "operationId": "list_companies_v1_companies_get",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Country"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Status"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Search"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "title": "Limit"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "include_address",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "description": "Resolve each row's legalAddressId in parallel (adds N round-trips). Set false for a faster, lighter list.",
              "default": true,
              "title": "Include Address"
            },
            "description": "Resolve each row's legalAddressId in parallel (adds N round-trips). Set false for a faster, lighter list."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated companies the API key is allowed to see.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_CompanyResponse_"
                },
                "example": {
                  "data": [
                    {
                      "id": "019a6e5b-3960-7000-ab88-153aed5a6240",
                      "organizationId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                      "name": "HOZELOCK EXEL",
                      "slug": "hozelock-exel",
                      "legalName": "HOZELOCK EXEL",
                      "country": "FR",
                      "vatNumber": "FR02779658772",
                      "taxNumber": "FR02779658772",
                      "registrationNumber": "77965877200024",
                      "legalAddressId": "019a6e5b-3b4c-7000-a460-a09181acc257",
                      "address": {
                        "street": "891 ROUTE DES FRENES",
                        "streetLine2": "Z.I.DE JOUX ARNAS NORD",
                        "city": "ARNAS",
                        "postalCode": "69400",
                        "country": "FR"
                      },
                      "isPublic": false,
                      "dataProviderType": "Whitepages",
                      "dataProviderSyncDate": "2025-11-10T15:21:04.068319Z",
                      "peppolId": "0009:02779658772",
                      "status": "active",
                      "smpRegistered": true,
                      "createdAt": "2025-11-10T15:21:03.581980Z",
                      "updatedAt": "2026-03-06T09:08:26.855434Z"
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/companies/import": {
      "post": {
        "tags": [
          "Companies"
        ],
        "summary": "Onboard a company for portability migration (SIRET-first)",
        "description": "Onboard a company for portability migration — keyed on the taxpayer's SIRET.\n\nIn the portal flow the taxpayer files a request giving **only its SIRET**.\nFlowie derives the SIREN, country (FR) and Peppol id (`0009:<siren>`),\nresolves the legal name (and current PA) from the PPF annuaire, then attaches\nthe company to its compliance backend:\n\n- **provision** on Sovos when a Sovos org is known (request field or the\n  configured `SOVOS_ORGANIZATION_ID`),\n- **import** an existing Sovos company when a `sovosCompanyId` is supplied,\n- or register **locally as pending** when no Sovos org is known (never\n  hard-fails). Emits `company.imported` / `company.import.pending`.\n\n**Example request (portal — SIRET only):**\n```http\nPOST /v1/companies/import\nContent-Type: application/json\n\n{ \"siret\": \"92137626500018\" }\n```\n\n**Example request (import an existing Sovos company):**\n```json\n{\n  \"sovosOrganizationId\": \"SOVOS-ORG-1\",\n  \"sovosCompanyId\": \"SOVOS-CMP-42\",\n  \"companyName\": \"HOZELOCK EXEL\",\n  \"countryCode\": \"FR\"\n}\n```\n\n**Example response (201):**\n```json\n{\n  \"id\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n  \"name\": \"FLOWIE\",\n  \"country\": \"FR\",\n  \"peppolId\": \"0009:921376265\",\n  \"status\": \"active\",\n  \"smpRegistered\": true\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | No `siret`/`siren` and no `sovosCompanyId`.                   |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 422    | `validation_error`     | Body failed schema validation.                                |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Sovos / org-v2 returned a non-2xx or unexpected response.     |\n| 503    | `upstream_unavailable` | Sovos integration not configured / unreachable.               |",
        "operationId": "import_company_v1_companies_import_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanyImportRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Company onboarded (imported or provisioned), linked in org-v2 and its Peppol registration set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyResponse"
                },
                "example": {
                  "id": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "organizationId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "name": "HOZELOCK EXEL",
                  "slug": "hozelock-exel",
                  "legalName": "HOZELOCK EXEL",
                  "country": "FR",
                  "vatNumber": "FR02779658772",
                  "taxNumber": "FR02779658772",
                  "registrationNumber": "77965877200024",
                  "legalAddressId": "019a6e5b-3b4c-7000-a460-a09181acc257",
                  "address": {
                    "street": "891 ROUTE DES FRENES",
                    "streetLine2": "Z.I.DE JOUX ARNAS NORD",
                    "city": "ARNAS",
                    "postalCode": "69400",
                    "country": "FR"
                  },
                  "isPublic": false,
                  "dataProviderType": "Whitepages",
                  "dataProviderSyncDate": "2025-11-10T15:21:04.068319Z",
                  "peppolId": "0009:02779658772",
                  "status": "active",
                  "smpRegistered": true,
                  "createdAt": "2025-11-10T15:21:03.581980Z",
                  "updatedAt": "2026-03-06T09:08:26.855434Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/companies/import/batch": {
      "post": {
        "tags": [
          "Companies"
        ],
        "summary": "Import many Sovos companies in one call (bulk portability migration)",
        "description": "Import a list of existing Sovos companies (bulk onboarding for portability).\n\nEach item is a `CompanyImportRequest`; items are imported concurrently\n(bounded) and idempotently. A per-item failure is reported in that item's\nresult row instead of failing the whole call, so a partial batch still\nonboards every company it can.\n\nNote: the Sovos API has no \"list unimported companies\" endpoint, so the\ncaller supplies the `sovosCompanyId`s to import (e.g. from a portability\nwork-list).\n\n**Example request:**\n```http\nPOST /v1/companies/import/batch\nContent-Type: application/json\n\n{\n  \"items\": [\n    {\"sovosOrganizationId\": \"SOVOS-ORG-1\", \"sovosCompanyId\": \"CMP-1\", \"companyName\": \"ACME\", \"countryCode\": \"FR\"},\n    {\"sovosOrganizationId\": \"SOVOS-ORG-1\", \"sovosCompanyId\": \"CMP-2\", \"companyName\": \"BETA\", \"countryCode\": \"FR\"}\n  ]\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"results\": [\n    {\"index\": 0, \"sovosCompanyId\": \"CMP-1\", \"status\": \"imported\", \"companyId\": \"019a…\", \"peppolId\": \"0009:…\"},\n    {\"index\": 1, \"sovosCompanyId\": \"CMP-2\", \"status\": \"failed\", \"error\": \"Sovos import returned no taxId\"}\n  ],\n  \"imported\": 1,\n  \"failed\": 1\n}\n```",
        "operationId": "import_companies_batch_v1_companies_import_batch_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanyImportBatchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-item import results (order preserved); per-item failures do not abort the batch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyImportBatchResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/companies/resolve": {
      "get": {
        "tags": [
          "Companies"
        ],
        "summary": "Resolve (and lazily create) a company from VAT / SIREN",
        "description": "Resolve a company from VAT or registration number, creating it in Flowie if absent.\n\nUsed by partner-onboarding flows that want a single-call \"find-or-create\" against\nthe public registries (PPF annuaire for FR, BCE for BE, etc.). At least one of\n`vatNumber` / `registrationNumber` must be provided alongside `countryCode`.\n\n**Example request:**\n```http\nGET /v1/companies/resolve?countryCode=FR&vatNumber=FR26921376265\n```\n\n**Example response (200):**\n```json\n{\n  \"id\": \"019a6e5b-3960-7000-ab88-153aed5a6241\",\n  \"name\": \"FLOWIE\",\n  \"country\": \"FR\",\n  \"vatNumber\": \"FR26921376265\",\n  \"registrationNumber\": \"921376265\",\n  \"peppolId\": \"0009:921376265\",\n  \"status\": \"active\"\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | Neither identifier given, unsupported country code.           |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `companies:write`.                                  |\n| 422    | `validation_error`     | Query failed schema validation.                               |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Registry / org-v2 returned a non-2xx response.                |\n| 503    | `upstream_unavailable` | Registry / org-v2 unreachable / timed out.                    |",
        "operationId": "resolve_company_v1_companies_resolve_get",
        "parameters": [
          {
            "name": "countryCode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "ISO 3166-1 alpha-2 country code (e.g. FR, BE, DE).",
              "title": "Countrycode"
            },
            "description": "ISO 3166-1 alpha-2 country code (e.g. FR, BE, DE)."
          },
          {
            "name": "vatNumber",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "VAT number — with or without the country prefix.",
              "title": "Vatnumber"
            },
            "description": "VAT number — with or without the country prefix."
          },
          {
            "name": "registrationNumber",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "National registration number (e.g. French SIREN, Belgian CBE).",
              "title": "Registrationnumber"
            },
            "description": "National registration number (e.g. French SIREN, Belgian CBE)."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Resolved (or newly created) company profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyResponse"
                },
                "example": {
                  "id": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "organizationId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "name": "HOZELOCK EXEL",
                  "slug": "hozelock-exel",
                  "legalName": "HOZELOCK EXEL",
                  "country": "FR",
                  "vatNumber": "FR02779658772",
                  "taxNumber": "FR02779658772",
                  "registrationNumber": "77965877200024",
                  "legalAddressId": "019a6e5b-3b4c-7000-a460-a09181acc257",
                  "address": {
                    "street": "891 ROUTE DES FRENES",
                    "streetLine2": "Z.I.DE JOUX ARNAS NORD",
                    "city": "ARNAS",
                    "postalCode": "69400",
                    "country": "FR"
                  },
                  "isPublic": false,
                  "dataProviderType": "Whitepages",
                  "dataProviderSyncDate": "2025-11-10T15:21:04.068319Z",
                  "peppolId": "0009:02779658772",
                  "status": "active",
                  "smpRegistered": true,
                  "createdAt": "2025-11-10T15:21:03.581980Z",
                  "updatedAt": "2026-03-06T09:08:26.855434Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/companies/search": {
      "get": {
        "tags": [
          "Companies"
        ],
        "summary": "Autocomplete search in public registries (not yet in Flowie)",
        "description": "Autocomplete search in public registries for companies not yet in Flowie.\n\nHits the country-appropriate registry (PPF annuaire for FR, etc.) and returns\nlightweight hits suitable for an autocomplete dropdown. Use `/resolve` once the\nuser picks a row to materialize the company in Flowie.\n\n**Example request:**\n```http\nGET /v1/companies/search?q=Flowie&countryCode=FR&limit=5\n```\n\n**Example response (200):**\n```json\n[\n  {\n    \"name\": \"FLOWIE\",\n    \"vatNumber\": \"FR26921376265\",\n    \"registrationNumber\": \"921376265\",\n    \"country\": \"FR\",\n    \"address\": {\"city\": \"PARIS\", \"postalCode\": \"75008\", \"country\": \"FR\"},\n    \"source\": \"ppf-annuaire\"\n  }\n]\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | `countryCode` not supported by any indexed registry.          |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `companies:read`.                                   |\n| 422    | `validation_error`     | Query failed schema validation.                               |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Registry returned a non-2xx response.                         |\n| 503    | `upstream_unavailable` | Registry unreachable / timed out.                             |",
        "operationId": "search_companies_v1_companies_search_get",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Free-text query — matched as a company name in the upstream registry.",
              "title": "Q"
            },
            "description": "Free-text query — matched as a company name in the upstream registry."
          },
          {
            "name": "countryCode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "ISO 3166-1 alpha-2 country code — required by the upstream registry index",
              "title": "Countrycode"
            },
            "description": "ISO 3166-1 alpha-2 country code — required by the upstream registry index"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Maximum number of results to return (1–100).",
              "default": 10,
              "title": "Limit"
            },
            "description": "Maximum number of results to return (1–100)."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Up to `limit` registry hits, ordered by registry relevance.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "title": "Response Search Companies V1 Companies Search Get"
                },
                "example": [
                  {
                    "name": "FLOWIE",
                    "vatNumber": "FR26921376265",
                    "registrationNumber": "921376265",
                    "country": "FR",
                    "address": {
                      "city": "PARIS",
                      "postalCode": "75008",
                      "country": "FR"
                    },
                    "source": "ppf-annuaire"
                  },
                  {
                    "name": "FLOWIE SOLUTIONS",
                    "vatNumber": "FR40303265045",
                    "registrationNumber": "303265045",
                    "country": "FR",
                    "address": {
                      "city": "PARIS",
                      "postalCode": "75008",
                      "country": "FR"
                    },
                    "source": "ppf-annuaire"
                  }
                ]
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/companies/join-requests": {
      "get": {
        "tags": [
          "Companies"
        ],
        "summary": "List the current user's pending join requests",
        "description": "List the calling user's outbound join requests in `pending` state.\n\nOnly meaningful for JWT auth — API keys are already bound to an organization.\nUse the per-company `/{id}/join-requests/{request_id}/accept|reject` routes (as\nan org admin) to act on inbound requests.\n\n**Example request:**\n```http\nGET /v1/companies/join-requests\n```\n\n**Example response (200):**\n```json\n[\n  {\n    \"id\": \"jr_01HX2K8...\",\n    \"companyId\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n    \"companyName\": \"HOZELOCK EXEL\",\n    \"status\": \"pending\",\n    \"createdAt\": \"2026-06-10T08:11:00Z\"\n  }\n]\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | API key auth (no user identity attached).                     |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Org-v2 returned a non-2xx response.                           |\n| 503    | `upstream_unavailable` | Org-v2 unreachable / timed out.                               |",
        "operationId": "list_join_requests_v1_companies_join_requests_get",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pending join requests issued by the calling user.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "title": "Response List Join Requests V1 Companies Join Requests Get"
                },
                "example": [
                  {
                    "id": "jr_01HX2K8...",
                    "companyId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                    "companyName": "HOZELOCK EXEL",
                    "requesterUserId": "user_01HX...",
                    "requesterEmail": "alice@example.com",
                    "status": "pending",
                    "createdAt": "2026-06-10T08:11:00Z"
                  }
                ]
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/companies/{company_id}": {
      "get": {
        "tags": [
          "Companies"
        ],
        "summary": "Get a company by id, `vat:<VAT>`, or `peppol:<scheme:id>`",
        "description": "Fetch a company by its Flowie id, or by `vat:<VAT>` / `peppol:<scheme:id>` alias.\n\nThe path parameter accepts three forms — a UUID/slug, `vat:FR26921376265`, or\n`peppol:0009:921376265`. The service joins the org-v2 organization record with\nthe local `PeppolRegistration` to surface `peppolId`, `status`, `smpRegistered`,\ncapabilities and stats in a single payload.\n\n**Example request:**\n```http\nGET /v1/companies/peppol:0009:921376265\n```\n\n**Example response (200):** see the example body above.\n\n**Example error (404):**\n```json\n{\n  \"type\": \"not_found\",\n  \"code\": \"company_not_found\",\n  \"message\": \"No company matches 'peppol:0009:921376265' in this organization.\",\n  \"details\": [],\n  \"requestId\": \"req_01HX...\"\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | Identifier prefix malformed.                                  |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `companies:read`.                                   |\n| 404    | `company_not_found`    | No matching company in org-v2 or local registrations.         |\n| 422    | `validation_error`     | Path validation failed.                                       |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Org-v2 returned a non-2xx response.                           |\n| 503    | `upstream_unavailable` | Org-v2 unreachable / timed out.                               |",
        "operationId": "get_company_v1_companies__company_id__get",
        "parameters": [
          {
            "name": "company_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Company Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full company profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyResponse"
                },
                "example": {
                  "id": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "organizationId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "name": "HOZELOCK EXEL",
                  "slug": "hozelock-exel",
                  "legalName": "HOZELOCK EXEL",
                  "country": "FR",
                  "vatNumber": "FR02779658772",
                  "taxNumber": "FR02779658772",
                  "registrationNumber": "77965877200024",
                  "legalAddressId": "019a6e5b-3b4c-7000-a460-a09181acc257",
                  "address": {
                    "street": "891 ROUTE DES FRENES",
                    "streetLine2": "Z.I.DE JOUX ARNAS NORD",
                    "city": "ARNAS",
                    "postalCode": "69400",
                    "country": "FR"
                  },
                  "isPublic": false,
                  "dataProviderType": "Whitepages",
                  "dataProviderSyncDate": "2025-11-10T15:21:04.068319Z",
                  "peppolId": "0009:02779658772",
                  "status": "active",
                  "smpRegistered": true,
                  "createdAt": "2025-11-10T15:21:03.581980Z",
                  "updatedAt": "2026-03-06T09:08:26.855434Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Company not found in org-v2 nor in local Peppol registrations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Companies"
        ],
        "summary": "Update a company (partial / JSON merge-patch semantics)",
        "description": "Partially update a company. Only fields present in the body are written.\n\nNested dict fields (`capabilities`, `settings`, `compliance`, `metadata`) are\nshallow-merged with the existing value; pass an explicit `null` to clear a\nnested key. Pure org-v2 fields are forwarded to org-v2; Peppol-specific fields\nare persisted on the local `PeppolRegistration`.\n\n**Example request:**\n```http\nPATCH /v1/companies/019a6e5b-3960-7000-ab88-153aed5a6240\nContent-Type: application/json\n\n{\n  \"name\": \"HOZELOCK EXEL (renamed)\",\n  \"metadata\": {\"erpId\": \"SAP-001\"}\n}\n```\n\n**Example response (200):** the updated company — see body above.\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | Malformed field value.                                        |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `companies:write`.                                  |\n| 404    | `company_not_found`    | No matching company.                                          |\n| 422    | `validation_error`     | Body failed schema validation.                                |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Org-v2 returned a non-2xx response.                           |\n| 503    | `upstream_unavailable` | Org-v2 unreachable / timed out.                               |",
        "operationId": "update_company_v1_companies__company_id__patch",
        "parameters": [
          {
            "name": "company_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Company Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanyUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated company profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyResponse"
                },
                "example": {
                  "id": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "organizationId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "name": "HOZELOCK EXEL (renamed)",
                  "slug": "hozelock-exel",
                  "legalName": "HOZELOCK EXEL",
                  "country": "FR",
                  "vatNumber": "FR02779658772",
                  "taxNumber": "FR02779658772",
                  "registrationNumber": "77965877200024",
                  "legalAddressId": "019a6e5b-3b4c-7000-a460-a09181acc257",
                  "address": {
                    "street": "891 ROUTE DES FRENES",
                    "streetLine2": "Z.I.DE JOUX ARNAS NORD",
                    "city": "ARNAS",
                    "postalCode": "69400",
                    "country": "FR"
                  },
                  "isPublic": false,
                  "dataProviderType": "Whitepages",
                  "dataProviderSyncDate": "2025-11-10T15:21:04.068319Z",
                  "peppolId": "0009:02779658772",
                  "status": "active",
                  "smpRegistered": true,
                  "createdAt": "2025-11-10T15:21:03.581980Z",
                  "updatedAt": "2026-03-06T09:08:26.855434Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Company not found in org-v2 nor in local Peppol registrations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Companies"
        ],
        "summary": "Deregister a company from Peppol",
        "description": "Deregister a company from Peppol — marks the local registration inactive and\ntears down the Sovos managed connection (where applicable).\n\nReturns `204 No Content` on success. The org-v2 organization record is preserved\n(it is not Flowie-owned) — only the Peppol-side registration is removed.\n\n**Example request:**\n```http\nDELETE /v1/companies/019a6e5b-3960-7000-ab88-153aed5a6240\n```\n\n**Errors** (body follows `ErrorResponse` except for 204):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 204    | —                      | Company deregistered (no body).                               |\n| 400    | `invalid_request`      | Identifier prefix malformed.                                  |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `companies:write`.                                  |\n| 404    | `company_not_found`    | No matching company.                                          |\n| 422    | `validation_error`     | Path validation failed.                                       |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Sovos / org-v2 returned a non-2xx response.                   |\n| 503    | `upstream_unavailable` | Sovos / org-v2 unreachable / timed out.                       |",
        "operationId": "deregister_company_v1_companies__company_id__delete",
        "parameters": [
          {
            "name": "company_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Company Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Company deregistered from Peppol (no body)."
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Company not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/companies/{company_id}/register": {
      "post": {
        "tags": [
          "Companies"
        ],
        "summary": "Deploy a company on Peppol (via Sovos) and activate registration",
        "description": "Deploy a company on Peppol (via Sovos) and activate its registration so it can send.\n\nIdempotent: for an org already provisioned on Sovos this just re-syncs and\nactivates the local registration; for a new org it provisions the Sovos\ncustomer config + managed connection (needs a genuine `sovosOrganizationId`).\n\n**Example request — re-activate existing registration:**\n```http\nPOST /v1/companies/019a6e5b-3960-7000-ab88-153aed5a6240/register\nContent-Type: application/json\n\n{}\n```\n\n**Example request — first-time provision:**\n```http\nPOST /v1/companies/019a6e5b-3960-7000-ab88-153aed5a6240/register\nContent-Type: application/json\n\n{\n  \"sovosOrganizationId\": \"sovos-org-12345\",\n  \"sovosProduct\": \"compliancenetwork\",\n  \"mode\": \"managed\"\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"id\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n  \"peppolId\": \"0009:02779658772\",\n  \"status\": \"active\",\n  \"smpRegistered\": true,\n  \"smpRegisteredAt\": \"2026-06-17T09:00:00Z\"\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | `sovosOrganizationId` missing for a new provision.            |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `companies:write`.                                  |\n| 404    | `company_not_found`    | No matching company.                                          |\n| 422    | `validation_error`     | Body failed schema validation.                                |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Sovos / SMP returned a non-2xx response.                      |\n| 503    | `upstream_unavailable` | Sovos / SMP unreachable / timed out.                          |",
        "operationId": "register_company_v1_companies__company_id__register_post",
        "parameters": [
          {
            "name": "company_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Company Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/CompanyRegisterRequest"
                  },
                  {
                    "type": "null"
                  }
                ],
                "title": "Body"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Company provisioned and registration activated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanyResponse"
                },
                "example": {
                  "id": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "organizationId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "name": "HOZELOCK EXEL",
                  "slug": "hozelock-exel",
                  "legalName": "HOZELOCK EXEL",
                  "country": "FR",
                  "vatNumber": "FR02779658772",
                  "taxNumber": "FR02779658772",
                  "registrationNumber": "77965877200024",
                  "legalAddressId": "019a6e5b-3b4c-7000-a460-a09181acc257",
                  "address": {
                    "street": "891 ROUTE DES FRENES",
                    "streetLine2": "Z.I.DE JOUX ARNAS NORD",
                    "city": "ARNAS",
                    "postalCode": "69400",
                    "country": "FR"
                  },
                  "isPublic": false,
                  "dataProviderType": "Whitepages",
                  "dataProviderSyncDate": "2025-11-10T15:21:04.068319Z",
                  "peppolId": "0009:02779658772",
                  "status": "active",
                  "smpRegistered": true,
                  "createdAt": "2025-11-10T15:21:03.581980Z",
                  "updatedAt": "2026-03-06T09:08:26.855434Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Company not found in org-v2 nor in local Peppol registrations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/companies/{company_id}/join": {
      "post": {
        "tags": [
          "Companies"
        ],
        "summary": "Request to join a company (as the calling user)",
        "description": "Request to join a Flowie company as the calling user.\n\nRequires JWT (user-bound) auth — API keys are already bound to a single org and\ncannot file join requests. An org admin then accepts or rejects via the\n`/{id}/join-requests/{request_id}/accept|reject` routes.\n\n**Example request:**\n```http\nPOST /v1/companies/019a6e5b-3960-7000-ab88-153aed5a6240/join\n```\n\n**Example response (201):**\n```json\n{\n  \"id\": \"jr_01HX2K8...\",\n  \"companyId\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n  \"status\": \"pending\",\n  \"createdAt\": \"2026-06-17T09:00:00Z\"\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | Identifier prefix malformed.                                  |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | API key auth (no user identity attached).                     |\n| 404    | `company_not_found`    | No matching company.                                          |\n| 409    | `conflict`             | User already a member, or has a pending request.              |\n| 422    | `validation_error`     | Path validation failed.                                       |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Org-v2 returned a non-2xx response.                           |\n| 503    | `upstream_unavailable` | Org-v2 unreachable / timed out.                               |",
        "operationId": "request_join_v1_companies__company_id__join_post",
        "parameters": [
          {
            "name": "company_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Company Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Join request created and queued for an org admin's decision.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Request Join V1 Companies  Company Id  Join Post"
                },
                "example": {
                  "id": "jr_01HX2K8...",
                  "companyId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "status": "pending",
                  "createdAt": "2026-06-17T09:00:00Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Company or join request not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict — request already pending / already a member / already resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/companies/{company_id}/join-requests/{request_id}/accept": {
      "post": {
        "tags": [
          "Companies"
        ],
        "summary": "Accept a pending join request (org admin)",
        "description": "Accept a pending join request for a company. Requires admin scope in the target org.\n\nOn success the requesting user is granted membership in org-v2 with the default\nmember role; the join request transitions to `status=\"accepted\"`.\n\n**Example request:**\n```http\nPOST /v1/companies/019a6e5b-3960-7000-ab88-153aed5a6240/join-requests/jr_01HX2K8.../accept\n```\n\n**Example response (200):**\n```json\n{\n  \"id\": \"jr_01HX2K8...\",\n  \"companyId\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n  \"status\": \"accepted\",\n  \"decidedAt\": \"2026-06-12T09:15:00Z\"\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | Malformed ids.                                                |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Caller is not an org admin.                                   |\n| 404    | `not_found`            | Company or join request not found.                            |\n| 409    | `conflict`             | Request already resolved.                                     |\n| 422    | `validation_error`     | Path validation failed.                                       |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Org-v2 returned a non-2xx response.                           |\n| 503    | `upstream_unavailable` | Org-v2 unreachable / timed out.                               |",
        "operationId": "accept_join_request_v1_companies__company_id__join_requests__request_id__accept_post",
        "parameters": [
          {
            "name": "company_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Company Id"
            }
          },
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Request Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Join request accepted; requester is now a member.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Accept Join Request V1 Companies  Company Id  Join Requests  Request Id  Accept Post"
                },
                "example": {
                  "id": "jr_01HX2K8...",
                  "companyId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "status": "accepted",
                  "decidedAt": "2026-06-12T09:15:00Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Company or join request not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict — request already pending / already a member / already resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/companies/{company_id}/join-requests/{request_id}/reject": {
      "post": {
        "tags": [
          "Companies"
        ],
        "summary": "Reject a pending join request (org admin)",
        "description": "Reject a pending join request for a company. Requires admin scope in the target org.\n\nThe join request transitions to `status=\"rejected\"`; the requester is *not*\ngranted membership and may not re-request until the rejection is cleared.\n\n**Example request:**\n```http\nPOST /v1/companies/019a6e5b-3960-7000-ab88-153aed5a6240/join-requests/jr_01HX2K8.../reject\n```\n\n**Example response (200):**\n```json\n{\n  \"id\": \"jr_01HX2K8...\",\n  \"companyId\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n  \"status\": \"rejected\",\n  \"decidedAt\": \"2026-06-12T09:15:00Z\"\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | Malformed ids.                                                |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Caller is not an org admin.                                   |\n| 404    | `not_found`            | Company or join request not found.                            |\n| 409    | `conflict`             | Request already resolved.                                     |\n| 422    | `validation_error`     | Path validation failed.                                       |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Org-v2 returned a non-2xx response.                           |\n| 503    | `upstream_unavailable` | Org-v2 unreachable / timed out.                               |",
        "operationId": "reject_join_request_v1_companies__company_id__join_requests__request_id__reject_post",
        "parameters": [
          {
            "name": "company_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Company Id"
            }
          },
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Request Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Join request rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Reject Join Request V1 Companies  Company Id  Join Requests  Request Id  Reject Post"
                },
                "example": {
                  "id": "jr_01HX2K8...",
                  "companyId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "status": "rejected",
                  "decidedAt": "2026-06-12T09:15:00Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (org-v2 / Sovos / Peppol Directory) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Company or join request not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict — request already pending / already a member / already resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/send": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Send a document (invoice, credit-note, order, quote, event) over Peppol",
        "description": "Send a document over Peppol (or record an event).\n\nTwo request modes are supported, selected by whether the URL has `type=…`:\n\n1. **Structured JSON mode** (default) — POST a JSON body matching\n   `SendDocumentRequest`. The server picks the right pipeline based on\n   `format`: `json` builds UBL from structured fields, `ubl-xml` /\n   `cii-xml` validates a raw XML body, `auto` sniffs `file.content` magic\n   bytes, and `raw` stores the file as-is without Peppol routing.\n2. **Raw-body mode** — pass `type`/`from`/`contentType`/`filename` as\n   query parameters and put the raw ERP payload (UBL/CII XML, PDF,\n   image, proprietary file) in the request body verbatim. The server\n   wraps it into a `FileAttachment` and delegates to the same pipeline.\n\nPass an `Idempotency-Key` header (any opaque string ≤ 255 chars) to\ndeduplicate retries: subsequent requests with the same key return the\ncached response without re-sending.\n\n---\n\n**Example request — JSON mode (structured invoice):**\n```json\n{\n  \"type\": \"invoice\",\n  \"format\": \"json\",\n  \"from\": \"0009:FR86797978996\",\n  \"to\": \"0208:0123456789\",\n  \"document\": {\n    \"number\": \"INV-2026-0042\",\n    \"issueDate\": \"2026-04-15\",\n    \"currency\": \"EUR\",\n    \"lines\": [\n      {\"description\": \"Consulting services\", \"quantity\": 10.0, \"unitPrice\": 150.00, \"vatRate\": 21.0}\n    ]\n  }\n}\n```\n\n**Example request — raw-body mode (UBL XML upload):**\n```\nPOST /v1/documents/send?type=invoice&from=0009:FR86797978996&contentType=application/xml&filename=INV-2026-0042.xml\nContent-Type: application/xml\n\n<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\">…</Invoice>\n```\n\n**Example response (201):**\n```json\n{\n  \"id\": \"doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6\",\n  \"status\": \"sent\",\n  \"type\": \"INVOICE\",\n  \"number\": \"INV-2026-0042\",\n  \"from\": {\"peppolId\": \"0009:FR86797978996\", \"name\": \"FLOWIE\", \"companyId\": \"comp_abc123\"},\n  \"to\": {\"peppolId\": \"0208:0123456789\", \"name\": \"ACME BELGIUM\"},\n  \"totals\": {\"net\": 1500.00, \"vat\": 315.00, \"gross\": 1815.00, \"currency\": \"EUR\"},\n  \"deliveryStatus\": \"delivered\",\n  \"sentAt\": \"2026-04-15T10:32:18.421Z\",\n  \"fileId\": null,\n  \"storedFormat\": null\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`   | Malformed JSON body, unknown `type`, unresolvable `from`/`to`.    |\n| 400    | `validation_error`  | Required field missing (`document.lines` for an invoice, etc.).   |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | `from` resolves to an organization the key doesn't own.           |\n| 422    | `validation_error`  | Body failed schema validation (legacy handler).                   |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected server error.                                          |\n| 502    | `upstream_error`    | tx-docs / documents / converter returned a non-2xx response.      |\n| 503    | `upstream_unavailable` | Upstream service unreachable / timed out.                      |",
        "operationId": "send_document_v1_documents_send_post",
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Type"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "From"
            }
          },
          {
            "name": "contentType",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Contenttype"
            }
          },
          {
            "name": "filename",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Filename"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Idempotency-Key"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Document accepted for delivery. In sandbox mode the response is synthesized synchronously; in live mode `deliveryStatus` may still be `pending` until the Peppol access point confirms the MLR.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendDocumentResponse"
                },
                "example": {
                  "id": "doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6",
                  "status": "sent",
                  "type": "INVOICE",
                  "number": "INV-2026-0042",
                  "from": {
                    "peppolId": "0009:FR86797978996",
                    "name": "FLOWIE",
                    "companyId": "comp_abc123"
                  },
                  "to": {
                    "peppolId": "0208:0123456789",
                    "name": "ACME BELGIUM"
                  },
                  "totals": {
                    "net": 1500.0,
                    "vat": 315.0,
                    "gross": 1815.0,
                    "currency": "EUR"
                  },
                  "deliveryStatus": "delivered",
                  "sentAt": "2026-04-15T10:32:18.421Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or query — malformed JSON, unknown document `type`, unresolvable `from`/`to` identifier, conflicting filters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document or sender belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (tx-docs, validator, converter, inbox) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "Structured JSON mode (default). Omit this body and instead pass `type`/`from`/`contentType`/`filename` as query parameters to use raw-body mode, where the request body is the native ERP payload (UBL/CII XML, PDF, image, proprietary file) verbatim.",
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type",
                  "from"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "invoice",
                      "credit-note",
                      "debit-note",
                      "purchase-order",
                      "purchase-request",
                      "sales-order",
                      "quote",
                      "event"
                    ]
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "json",
                      "ubl-xml",
                      "cii-xml",
                      "auto",
                      "raw"
                    ],
                    "description": "Defaults to json."
                  },
                  "from": {
                    "type": "string",
                    "description": "Sender company. Bare Peppol id (0208:0123456789) or peppol:… / vat:… / comp_… / org:… — normalised to the canonical Peppol id before delivery."
                  },
                  "to": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Recipient. A Peppol id (0208:… / peppol:…) used as-is, or any resolvable identifier: vat:, siren:/siret:, duns:, gln:, lei:, eori:, email:, domain:, name:, org:/id: (or their bare forms). Non-Peppol ids are resolved (and provisioned if never seen) to a routable participant. Required unless type=event."
                  },
                  "document": {
                    "$ref": "#/components/schemas/DocumentBody"
                  },
                  "xml": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "file": {
                    "$ref": "#/components/schemas/FileAttachment"
                  },
                  "selfBilled": {
                    "type": "boolean",
                    "description": "Self-billed invoice (autofacturation): the acting org (from) is the customer issuing on the supplier's behalf, so `to` becomes the Seller and `from` the Buyer/initiator. Tags the document UNCL1001 389. Only valid for type=invoice. Default false."
                  },
                  "documentSubtype": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "UNCL1001 document subtype, rendered as the UBL InvoiceTypeCode (BT-3). For invoice sub-kinds beyond the plain commercial invoice (380): PREPAYMENT_INVOICE (386 - facture d'acompte), CORRECTED_INVOICE (384 - facture rectificative), SELF_BILLED_INVOICE (389). Accepts the CAPITAL_SNAKE_CASE name or the raw code. Only for type=invoice."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/send/batch": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Send many documents in a single call",
        "description": "Send up to N documents in one HTTP round-trip. Each item is processed\nindependently; a 4xx on one item does not abort the rest — its error is\nsurfaced inline under `results[i].error` and the outer response is still\n200. Each item may carry its own `idempotencyKey` for safe retries.\n\n---\n\n**Example request:**\n```json\n{\n  \"documents\": [\n    {\n      \"idempotencyKey\": \"batch-1-item-1\",\n      \"type\": \"invoice\",\n      \"from\": \"0009:FR86797978996\",\n      \"to\": \"0208:0123456789\",\n      \"document\": {\n        \"number\": \"INV-2026-0042\",\n        \"issueDate\": \"2026-04-15\",\n        \"currency\": \"EUR\",\n        \"lines\": [{\"description\": \"Consulting\", \"quantity\": 10, \"unitPrice\": 150.0, \"vatRate\": 21.0}]\n      }\n    },\n    {\n      \"type\": \"credit-note\",\n      \"from\": \"0009:FR86797978996\",\n      \"to\": \"0208:0123456789\",\n      \"document\": {\"number\": \"CN-2026-0001\", \"issueDate\": \"2026-04-15\", \"currency\": \"EUR\"}\n    }\n  ]\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"results\": [\n    {\"id\": \"doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6\", \"status\": \"sent\", \"deliveryStatus\": \"delivered\", \"number\": \"INV-2026-0042\"},\n    {\"status\": \"error\", \"error\": {\"code\": 400, \"detail\": \"credit-note requires 'lines'\"}, \"type\": \"credit-note\"}\n  ],\n  \"summary\": {\"total\": 2, \"succeeded\": 1, \"failed\": 1}\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`   | `documents` empty or malformed at the envelope level.             |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | A `from` resolves to an organization the key doesn't own.         |\n| 422    | `validation_error`  | Body failed schema validation (legacy handler).                   |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected server error.                                          |\n| 502    | `upstream_error`    | Upstream tx-docs / documents service returned a non-2xx.          |\n| 503    | `upstream_unavailable` | Upstream service unreachable / timed out.                      |",
        "operationId": "batch_send_v1_documents_send_batch_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchSendRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-document results plus an aggregate summary. Individual failures do not abort the batch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchSendResponse"
                },
                "example": {
                  "results": [
                    {
                      "id": "doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6",
                      "status": "sent",
                      "deliveryStatus": "delivered",
                      "number": "INV-2026-0042"
                    },
                    {
                      "status": "error",
                      "error": {
                        "code": 400,
                        "detail": "'to' is required for type=invoice"
                      },
                      "type": "invoice"
                    }
                  ],
                  "summary": {
                    "total": 2,
                    "succeeded": 1,
                    "failed": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or query — malformed JSON, unknown document `type`, unresolvable `from`/`to` identifier, conflicting filters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document or sender belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (tx-docs, validator, converter, inbox) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/validate": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Validate a document body without sending it",
        "description": "Dry-run validate a document without persisting or sending it. For\n`format=ubl-xml` the payload is forwarded to the einvoice-validator\nservice (Schematron + EN16931 + national rules). For structured JSON\nonly minimal sanity checks run today (document body present, at least\none line) — full UBL generation + validation happens at send time.\n\nA `valid=false` response is still a 200 — clients should look at the\n`errors` array, not the HTTP status, to decide whether to proceed.\n\n---\n\n**Example request:**\n```json\n{\n  \"type\": \"invoice\",\n  \"format\": \"ubl-xml\",\n  \"from\": \"0009:FR86797978996\",\n  \"to\": \"0208:0123456789\",\n  \"xml\": \"<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\">…</Invoice>\"\n}\n```\n\n**Example response — valid (200):**\n```json\n{\"valid\": true, \"errors\": [], \"warnings\": [], \"preview\": null}\n```\n\n**Example response — invalid (200):**\n```json\n{\n  \"valid\": false,\n  \"errors\": [\n    {\"field\": \"/Invoice/AccountingSupplierParty\", \"rule\": \"BR-CO-26\", \"message\": \"Seller party is required\"}\n  ],\n  \"warnings\": [\n    {\"field\": \"/Invoice/PaymentMeans\", \"rule\": \"PEPPOL-EN16931-R061\", \"message\": \"IBAN should be uppercase\"}\n  ],\n  \"preview\": null\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`   | Malformed body or unsupported `format`.                           |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | `from` resolves to an org the key doesn't own.                    |\n| 422    | `validation_error`  | Body failed schema validation (legacy handler).                   |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected server error.                                          |\n| 502    | `upstream_error`    | einvoice-validator returned a non-2xx response.                   |\n| 503    | `upstream_unavailable` | einvoice-validator unreachable / timed out.                    |",
        "operationId": "validate_document_v1_documents_validate_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ValidateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation result. `valid=false` does NOT make this a 4xx — inspect `errors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidateResponse"
                },
                "example": {
                  "valid": false,
                  "errors": [
                    {
                      "field": "document.lines",
                      "rule": "min_items",
                      "message": "at least one line required"
                    }
                  ],
                  "warnings": []
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or query — malformed JSON, unknown document `type`, unresolvable `from`/`to` identifier, conflicting filters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document or sender belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (tx-docs, validator, converter, inbox) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "List documents with filters and cursor pagination",
        "description": "List documents the caller can see, with optional filters.\n\nFilters compose with AND semantics: `direction=incoming`, `type=INVOICE`,\n`deliveryStatus=delivered`, `status` (exact `lifecycleStatus`), `from`/`to`\n(issue-date range), `amountMin`/`amountMax`, `companyId`, and a free-text\n`search` against document number / sender / receiver name. Cursor-based\npagination — pass the `cursor` from the previous page to fetch the next one.\n\n`status` matches the document's exact `lifecycleStatus`, which is org-specific\nand may be localized — so prefer `deliveryStatus` for network delivery state.\n(`status=delivered` / `status=failed` are treated as `deliveryStatus`.)\n\n---\n\n**Example request — delivered incoming invoices:**\n```\nGET /v1/documents?direction=incoming&type=INVOICE&deliveryStatus=delivered&limit=20\n```\n\n**Example response (200):**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6\",\n      \"type\": \"INVOICE\",\n      \"direction\": \"outgoing\",\n      \"number\": \"INV-2026-0042\",\n      \"issueDate\": \"2026-04-15\",\n      \"dueDate\": \"2026-05-15\",\n      \"currency\": \"EUR\",\n      \"grossAmount\": 1815.00,\n      \"sender\": {\"peppolId\": \"0009:FR86797978996\", \"name\": \"FLOWIE\"},\n      \"receiver\": {\"peppolId\": \"0208:0123456789\", \"name\": \"ACME BELGIUM\"},\n      \"status\": \"sent\",\n      \"deliveryStatus\": \"delivered\",\n      \"receivedAt\": null\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`   | `cursor` malformed, `amountMin > amountMax`, unknown `type`.      |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | `companyId` belongs to another org.                               |\n| 422    | `validation_error`  | Query failed schema validation (non-numeric `limit`, etc.).       |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected server error.                                          |\n| 502    | `upstream_error`    | tx-docs returned a non-2xx response.                              |\n| 503    | `upstream_unavailable` | tx-docs unreachable / timed out.                               |",
        "operationId": "list_documents_v1_documents_get",
        "parameters": [
          {
            "name": "direction",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Direction"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Type"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Lifecycle status — matched against the document's exact `lifecycleStatus`, which is **org-specific and may be localized** (e.g. `draft`, `sent`, `Reçue par la plateforme`). The delivery-state values `delivered` / `failed` are routed to `deliveryStatus` instead. For network delivery state, prefer the `deliveryStatus` filter.",
              "title": "Status"
            },
            "description": "Lifecycle status — matched against the document's exact `lifecycleStatus`, which is **org-specific and may be localized** (e.g. `draft`, `sent`, `Reçue par la plateforme`). The delivery-state values `delivered` / `failed` are routed to `deliveryStatus` instead. For network delivery state, prefer the `deliveryStatus` filter."
          },
          {
            "name": "deliveryStatus",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Peppol delivery state: `pending`, `delivered`, `failed`, or `rejected`.",
              "title": "Deliverystatus"
            },
            "description": "Peppol delivery state: `pending`, `delivered`, `failed`, or `rejected`."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "From"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "To"
            }
          },
          {
            "name": "amountMin",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "number"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Amountmin"
            }
          },
          {
            "name": "amountMax",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "number"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Amountmax"
            }
          },
          {
            "name": "companyId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Companyid"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Search"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "title": "Limit"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of documents matching the filter set, ordered newest-first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_DocumentListItem_"
                },
                "example": {
                  "data": [
                    {
                      "id": "doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6",
                      "type": "INVOICE",
                      "direction": "outgoing",
                      "number": "INV-2026-0042",
                      "issueDate": "2026-04-15",
                      "dueDate": "2026-05-15",
                      "currency": "EUR",
                      "grossAmount": 1815.0,
                      "sender": {
                        "peppolId": "0009:FR86797978996",
                        "name": "FLOWIE"
                      },
                      "receiver": {
                        "peppolId": "0208:0123456789",
                        "name": "ACME BELGIUM"
                      },
                      "status": "sent",
                      "deliveryStatus": "delivered"
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or query — malformed JSON, unknown document `type`, unresolvable `from`/`to` identifier, conflicting filters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document or sender belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (tx-docs, validator, converter, inbox) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/search": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Search documents with a structured filter body (POST variant of GET /documents)",
        "description": "Search documents using a structured body instead of query parameters —\nuseful when filter combinations get long enough to bump into URL-length\nlimits, or when callers want to express complex `filters` / `sort`\nstructures without URL-encoding them.\n\n---\n\n**Example request:**\n```json\n{\n  \"query\": \"INV-2026\",\n  \"filters\": {\n    \"direction\": \"outgoing\",\n    \"type\": \"INVOICE\",\n    \"deliveryStatus\": \"delivered\",\n    \"issueDateFrom\": \"2026-01-01\"\n  },\n  \"sort\": {\"field\": \"issueDate\", \"order\": \"desc\"},\n  \"limit\": 20\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6\",\n      \"type\": \"INVOICE\",\n      \"direction\": \"outgoing\",\n      \"number\": \"INV-2026-0042\",\n      \"issueDate\": \"2026-04-15\",\n      \"dueDate\": \"2026-05-15\",\n      \"currency\": \"EUR\",\n      \"grossAmount\": 1815.00,\n      \"sender\": {\"peppolId\": \"0009:FR86797978996\", \"name\": \"FLOWIE\"},\n      \"receiver\": {\"peppolId\": \"0208:0123456789\", \"name\": \"ACME BELGIUM\"},\n      \"status\": \"sent\",\n      \"deliveryStatus\": \"delivered\",\n      \"receivedAt\": null\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`   | Malformed `filters` / `sort`, unknown field.                      |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | `companyId` filter belongs to another org.                        |\n| 422    | `validation_error`  | Body failed schema validation (legacy handler).                   |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected server error.                                          |\n| 502    | `upstream_error`    | tx-docs returned a non-2xx response.                              |\n| 503    | `upstream_unavailable` | tx-docs unreachable / timed out.                               |",
        "operationId": "search_documents_v1_documents_search_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Page of documents matching the search body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_DocumentListItem_"
                },
                "example": {
                  "data": [
                    {
                      "id": "doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6",
                      "type": "INVOICE",
                      "direction": "outgoing",
                      "number": "INV-2026-0042",
                      "issueDate": "2026-04-15",
                      "dueDate": "2026-05-15",
                      "currency": "EUR",
                      "grossAmount": 1815.0,
                      "sender": {
                        "peppolId": "0009:FR86797978996",
                        "name": "FLOWIE"
                      },
                      "receiver": {
                        "peppolId": "0208:0123456789",
                        "name": "ACME BELGIUM"
                      },
                      "status": "sent",
                      "deliveryStatus": "delivered"
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or query — malformed JSON, unknown document `type`, unresolvable `from`/`to` identifier, conflicting filters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document or sender belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (tx-docs, validator, converter, inbox) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{document_id}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Get the full nested representation of a single document",
        "description": "Return the complete document representation: header + nested\n`document` body (lines, totals, payment, etc.) + status + delivery\nmetadata. This is the canonical \"give me everything about doc X\" call\n— for a flat agent-friendly shape use `/{document_id}/structured`.\n\n---\n\n**Example response (200):**\n```json\n{\n  \"id\": \"doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6\",\n  \"type\": \"INVOICE\",\n  \"direction\": \"outgoing\",\n  \"number\": \"INV-2026-0042\",\n  \"issueDate\": \"2026-04-15\",\n  \"dueDate\": \"2026-05-15\",\n  \"currency\": \"EUR\",\n  \"grossAmount\": 1815.00,\n  \"netAmount\": 1500.00,\n  \"vatAmount\": 315.00,\n  \"sender\": {\"peppolId\": \"0009:FR86797978996\", \"name\": \"FLOWIE\"},\n  \"receiver\": {\"peppolId\": \"0208:0123456789\", \"name\": \"ACME BELGIUM\"},\n  \"status\": \"sent\",\n  \"deliveryStatus\": \"delivered\",\n  \"lifecycleStatus\": \"approved\",\n  \"sentAt\": \"2026-04-15T10:32:18.421Z\",\n  \"createdAt\": \"2026-04-15T10:32:00.000Z\",\n  \"updatedAt\": \"2026-04-15T10:32:18.421Z\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Document belongs to a different organization.                     |\n| 404    | `not_found`         | No document with that id.                                         |\n| 422    | `validation_error`  | Path id failed schema validation.                                 |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected server error.                                          |\n| 502    | `upstream_error`    | tx-docs returned a non-2xx response.                              |\n| 503    | `upstream_unavailable` | tx-docs unreachable / timed out.                               |",
        "operationId": "get_document_v1_documents__document_id__get",
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full document, including the nested `document` body and metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentResponse"
                },
                "example": {
                  "id": "doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6",
                  "type": "INVOICE",
                  "direction": "outgoing",
                  "number": "INV-2026-0042",
                  "issueDate": "2026-04-15",
                  "dueDate": "2026-05-15",
                  "currency": "EUR",
                  "grossAmount": 1815.0,
                  "netAmount": 1500.0,
                  "vatAmount": 315.0,
                  "sender": {
                    "peppolId": "0009:FR86797978996",
                    "name": "FLOWIE"
                  },
                  "receiver": {
                    "peppolId": "0208:0123456789",
                    "name": "ACME BELGIUM"
                  },
                  "status": "sent",
                  "deliveryStatus": "delivered",
                  "lifecycleStatus": "approved",
                  "sentAt": "2026-04-15T10:32:18.421Z",
                  "createdAt": "2026-04-15T10:32:00.000Z",
                  "updatedAt": "2026-04-15T10:32:18.421Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or query — malformed JSON, unknown document `type`, unresolvable `from`/`to` identifier, conflicting filters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document or sender belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (tx-docs, validator, converter, inbox) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Document id not found in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{document_id}/xml": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Download the canonical UBL XML for a document",
        "description": "Download the canonical UBL XML representation of a document — what\nactually traveled over Peppol. For inbound documents this is the\nreceived payload; for outbound it's what we generated and submitted.\nResponse media type is `application/xml`.\n\n---\n\n**Example request:**\n```\nGET /v1/documents/doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6/xml\nAccept: application/xml\n```\n\n**Example response (200, body):**\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\">\n  <cbc:ID>INV-2026-0042</cbc:ID>\n  <cbc:IssueDate>2026-04-15</cbc:IssueDate>\n  …\n</Invoice>\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Document belongs to a different organization.                     |\n| 404    | `not_found`         | No document with that id, or no XML payload stored.               |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected server error.                                          |\n| 502    | `upstream_error`    | documents service returned a non-2xx response.                    |\n| 503    | `upstream_unavailable` | documents service unreachable / timed out.                     |",
        "operationId": "get_document_xml_v1_documents__document_id__xml_get",
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Raw UBL XML bytes.",
            "content": {
              "application/json": {
                "schema": {}
              },
              "application/xml": {
                "example": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\">\n  <cbc:ID>INV-2026-0042</cbc:ID>\n  <cbc:IssueDate>2026-04-15</cbc:IssueDate>\n  …\n</Invoice>"
              }
            }
          },
          "400": {
            "description": "Invalid request body or query — malformed JSON, unknown document `type`, unresolvable `from`/`to` identifier, conflicting filters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document or sender belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (tx-docs, validator, converter, inbox) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Document id not found in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{document_id}/pdf": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Download a PDF rendering of a document",
        "description": "Download a PDF rendering of the document. For documents that\nalready had a PDF attached at send time (PDF/A-3 with embedded UBL)\nthe original PDF is returned verbatim; otherwise the document-\nconversion service renders one on the fly from the UBL XML. Response\nmedia type is `application/pdf`.\n\n---\n\n**Example request:**\n```\nGET /v1/documents/doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6/pdf\nAccept: application/pdf\n```\n\nReturns PDF bytes in the response body.\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Document belongs to a different organization.                     |\n| 404    | `not_found`         | No document with that id, or no renderable payload.               |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected server error.                                          |\n| 502    | `upstream_error`    | document-conversion service returned a non-2xx.                   |\n| 503    | `upstream_unavailable` | document-conversion service unreachable / timed out.           |",
        "operationId": "get_document_pdf_v1_documents__document_id__pdf_get",
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PDF bytes (`application/pdf`).",
            "content": {
              "application/json": {
                "schema": {}
              },
              "application/pdf": {}
            }
          },
          "400": {
            "description": "Invalid request body or query — malformed JSON, unknown document `type`, unresolvable `from`/`to` identifier, conflicting filters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document or sender belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (tx-docs, validator, converter, inbox) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Document id not found in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{document_id}/structured": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Get a flat agent-friendly view of a single document",
        "description": "Return a flat, primitives-only view of a document — everything an\nLLM agent or a tabular UI needs to render or reason about a doc, with\nno nested objects. Use this when you don't need the full UBL line\nbreakdown.\n\n---\n\n**Example response (200):** see the `responses` block above.\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Document belongs to a different organization.                     |\n| 404    | `not_found`         | No document with that id.                                         |\n| 422    | `validation_error`  | Path id failed schema validation.                                 |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected server error.                                          |\n| 502    | `upstream_error`    | tx-docs returned a non-2xx response.                              |\n| 503    | `upstream_unavailable` | tx-docs unreachable / timed out.                               |",
        "operationId": "get_document_structured_v1_documents__document_id__structured_get",
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Flat, primitives-only representation — ideal for LLM tool-use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StructuredDocumentResponse"
                },
                "example": {
                  "id": "doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6",
                  "type": "INVOICE",
                  "direction": "outgoing",
                  "number": "INV-2026-0042",
                  "issueDate": "2026-04-15",
                  "dueDate": "2026-05-15",
                  "currency": "EUR",
                  "grossAmount": 1815.0,
                  "netAmount": 1500.0,
                  "vatAmount": 315.0,
                  "status": "sent",
                  "lifecycleStatus": "approved",
                  "deliveryStatus": "delivered",
                  "senderPeppolId": "0009:FR86797978996",
                  "senderName": "FLOWIE",
                  "senderVatNumber": "FR26921376265",
                  "receiverPeppolId": "0208:0123456789",
                  "receiverName": "ACME BELGIUM",
                  "receiverVatNumber": "BE0123456789",
                  "buyerReference": "PO-2026-0815",
                  "orderReference": "ORD-2026-0042",
                  "paymentIban": "FR7630006000011234567890189",
                  "paymentReference": "INV-2026-0042",
                  "note": "Payment due in 30 days",
                  "sentAt": "2026-04-15T10:32:18.421Z",
                  "createdAt": "2026-04-15T10:32:00.000Z",
                  "updatedAt": "2026-04-15T10:32:18.421Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or query — malformed JSON, unknown document `type`, unresolvable `from`/`to` identifier, conflicting filters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document or sender belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (tx-docs, validator, converter, inbox) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Document id not found in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{document_id}/actions": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Perform an inbox-style action on a document (tag, archive, assign, link, …)",
        "description": "Apply a side-effectful action to a document — mark-read / mark-unread,\narchive / unarchive, tag / untag, assign / unassign, add-note, link.\nEach action maps to an upstream call (tags service, inbox service,\nchat service for notes, or a tx-docs relationship link).\n\n---\n\n**Example request — tag a document:**\n```json\n{\"action\": \"tag\", \"tag\": \"needs-review\"}\n```\n\n**Example request — assign to a user:**\n```json\n{\"action\": \"assign\", \"userId\": \"usr_5f2a8c\"}\n```\n\n**Example request — link to a related document:**\n```json\n{\"action\": \"link\", \"relatedDocumentId\": \"doc_71b3c8e4d9a2f5c8\"}\n```\n\n**Example response (200):** see `GET /v1/documents/{document_id}`.\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`   | Unknown `action`, or required field missing (e.g. `tag` for tag). |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Document belongs to a different organization.                     |\n| 404    | `not_found`         | No document with that id, or `relatedDocumentId` not found.       |\n| 422    | `validation_error`  | Body failed schema validation (legacy handler).                   |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected server error.                                          |\n| 502    | `upstream_error`    | tags / inbox / chat / tx-docs returned a non-2xx response.        |\n| 503    | `upstream_unavailable` | Upstream service unreachable / timed out.                      |",
        "operationId": "perform_action_v1_documents__document_id__actions_post",
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ActionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document after the action was applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentResponse"
                },
                "example": {
                  "id": "doc_01HF8K3JD9V2M8X7Q9N3R4T5Y6",
                  "type": "INVOICE",
                  "direction": "outgoing",
                  "number": "INV-2026-0042",
                  "issueDate": "2026-04-15",
                  "dueDate": "2026-05-15",
                  "currency": "EUR",
                  "grossAmount": 1815.0,
                  "netAmount": 1500.0,
                  "vatAmount": 315.0,
                  "sender": {
                    "peppolId": "0009:FR86797978996",
                    "name": "FLOWIE"
                  },
                  "receiver": {
                    "peppolId": "0208:0123456789",
                    "name": "ACME BELGIUM"
                  },
                  "status": "sent",
                  "deliveryStatus": "delivered",
                  "lifecycleStatus": "approved",
                  "sentAt": "2026-04-15T10:32:18.421Z",
                  "createdAt": "2026-04-15T10:32:00.000Z",
                  "updatedAt": "2026-04-15T10:32:18.421Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or query — malformed JSON, unknown document `type`, unresolvable `from`/`to` identifier, conflicting filters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document or sender belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (tx-docs, validator, converter, inbox) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Document id not found in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{document_id}/lifecycle": {
      "get": {
        "tags": [
          "Lifecycle"
        ],
        "summary": "Read a document's lifecycle history and current status",
        "description": "Return the lifecycle audit log for a document — every status the\ndocument has been in, who set it, when, with optional notes — plus the\ncurrent status, the set of legal next transitions, and any compliance\nreporting metadata (e.g. PPF acknowledgement for FR, SDI receipt for IT).\n\nThe state machine is:\n  `draft` / `received` → `under_review` → `approved` / `rejected`,\n  `approved` → `partially_paid` → `paid`, `approved` → `disputed`,\n  `disputed` → `approved` / `rejected`. Terminal states are `paid` and\n  `rejected`.\n\n---\n\n**Example response (200):**\n```json\n{\n  \"documentId\": \"doc_test001\",\n  \"currentStatus\": \"approved\",\n  \"currentStatusAt\": \"2026-04-15T10:32:18.421Z\",\n  \"compliance\": {},\n  \"history\": [\n    {\"status\": \"received\", \"at\": \"2026-04-14T09:12:03.100Z\", \"setBy\": \"system\", \"note\": null, \"reported\": false, \"reportedTo\": null, \"reportedAt\": null},\n    {\"status\": \"under_review\", \"at\": \"2026-04-14T14:08:45.220Z\", \"setBy\": \"usr_5f2a\", \"note\": \"Awaiting PO match\", \"reported\": false, \"reportedTo\": null, \"reportedAt\": null},\n    {\"status\": \"approved\", \"at\": \"2026-04-15T10:32:18.421Z\", \"setBy\": \"usr_5f2a\", \"note\": \"Invoice verified against PO\", \"reported\": false, \"reportedTo\": null, \"reportedAt\": null}\n  ],\n  \"allowedTransitions\": [\"partially_paid\", \"paid\", \"disputed\"]\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Document belongs to a different organization.                     |\n| 404    | `not_found`         | No document with that id.                                         |\n| 422    | `validation_error`  | Path id failed schema validation.                                 |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 502    | `upstream_error`    | tx-docs returned a non-2xx response when fetching the audit log.  |\n| 503    | `upstream_unavailable` | tx-docs unreachable / timed out.                               |",
        "operationId": "get_lifecycle_v1_documents__document_id__lifecycle_get",
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full lifecycle history + current state machine status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LifecycleHistoryResponse"
                },
                "example": {
                  "documentId": "doc_test001",
                  "currentStatus": "approved",
                  "currentStatusAt": "2026-04-15T10:32:18.421Z",
                  "compliance": {},
                  "history": [
                    {
                      "status": "received",
                      "at": "2026-04-14T09:12:03.100Z",
                      "setBy": "system",
                      "reported": false
                    },
                    {
                      "status": "under_review",
                      "at": "2026-04-14T14:08:45.220Z",
                      "setBy": "usr_5f2a",
                      "note": "Awaiting PO match",
                      "reported": false
                    },
                    {
                      "status": "approved",
                      "at": "2026-04-15T10:32:18.421Z",
                      "setBy": "usr_5f2a",
                      "note": "Invoice verified against PO",
                      "reported": false
                    }
                  ],
                  "allowedTransitions": [
                    "partially_paid",
                    "paid",
                    "disputed"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request — unknown `status`, illegal transition from the current state, or missing required payment fields for `status=paid`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document belongs to another organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream transaction-documents service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream transaction-documents service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Document id not found in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Lifecycle"
        ],
        "summary": "Transition a document to a new lifecycle status",
        "description": "Move a document to a new status. The target must be a legal successor\nof the current status in the finite-state machine\n(`ALLOWED_TRANSITIONS`) — illegal transitions return 400. For\nFR and IT documents the status change is also reported to the national\nCTC platform (PPF / SDI) and the upstream acknowledgement is surfaced\nin the response under `compliance`.\n\nPayment fields (`paymentDate`, `paymentAmount`, `paymentCurrency`,\n`paymentReference`) are required when `status=paid` or\n`status=partially_paid`.\n\nA coded reason (`reasonCode`) is required for `rejected` and `disputed`:\nuse one of the 14 official Peppol status reason codes (OPStatusReason) —\n`NON`, `REF`, `LEG`, `REC`, `QUA`, `DEL`, `PRI`, `QTY`, `ITM`, `PAY`,\n`UNR`, `FIN`, `PPD`, `OTH` — documented with their meanings at\n<https://docs.get-flowie.com/reference/#reason-codes>. On the French DGFiP\nleg the code is forwarded verbatim as MDT-113 (AFNOR XP Z12-012 motif),\nand `reasonCode=\"suspended\"` with `status=disputed` transmits\n208 Suspendue instead of 207.\n\n**Prioritize on hold over refusing directly.** `rejected` is terminal —\nthe supplier must issue a corrective invoice. If the disagreement may\nstill be resolved, send the reversible statuses first: `disputed`\n(contest) or `disputed` + `reasonCode=\"suspended\"` (on hold pending\ndocuments); both keep the invoice alive and resolve back to approval.\nWhichever you send, make the reason actionable: the code names the\nproblem, the free-text `reason` says exactly what is missing or wrong\n(line, expected value) so the supplier can fix it first time.\n\n---\n\n**Example request — approve an invoice:**\n```json\n{\n  \"status\": \"approved\",\n  \"note\": \"Invoice verified against PO\"\n}\n```\n\n**Example request — reject with a coded reason:**\n```json\n{\n  \"status\": \"rejected\",\n  \"reasonCode\": \"PRI\",\n  \"reason\": \"Unit price on line 3 does not match the quote\"\n}\n```\n\n**Example request — mark as paid:**\n```json\n{\n  \"status\": \"paid\",\n  \"paymentDate\": \"2026-04-15\",\n  \"paymentAmount\": 1815.00,\n  \"paymentCurrency\": \"EUR\",\n  \"paymentReference\": \"PAY-2026-0042\"\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"documentId\": \"doc_test001\",\n  \"previousStatus\": \"received\",\n  \"currentStatus\": \"approved\",\n  \"updatedAt\": \"2026-04-15T10:32:18.421Z\",\n  \"compliance\": {},\n  \"allowedTransitions\": [\"partially_paid\", \"paid\", \"disputed\"]\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `invalid_transition`| Target `status` is not in `ALLOWED_TRANSITIONS` from the current. |\n| 400    | `validation_error`  | Required payment field missing for `paid`/`partially_paid`.       |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Document belongs to a different organization.                     |\n| 404    | `not_found`         | No document with that id.                                         |\n| 422    | `validation_error`  | Body failed schema validation (legacy handler).                   |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 502    | `upstream_error`    | tx-docs or compliance platform (PPF/SDI) returned an error.       |\n| 503    | `upstream_unavailable` | tx-docs or compliance platform unreachable / timed out.        |",
        "operationId": "update_lifecycle_v1_documents__document_id__lifecycle_post",
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Document Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LifecycleUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status updated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LifecycleUpdateResponse"
                },
                "example": {
                  "documentId": "doc_test001",
                  "previousStatus": "received",
                  "currentStatus": "approved",
                  "updatedAt": "2026-04-15T10:32:18.421Z",
                  "compliance": {},
                  "allowedTransitions": [
                    "partially_paid",
                    "paid",
                    "disputed"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request — unknown `status`, illegal transition from the current state, or missing required payment fields for `status=paid`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document belongs to another organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream transaction-documents service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream transaction-documents service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Document id not found in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/by-number/{number}/lifecycle": {
      "post": {
        "tags": [
          "Lifecycle"
        ],
        "summary": "Transition a document to a new lifecycle status, targeted by invoice number",
        "description": "Move a document to a new status, targeting it by its **invoice number**\ninstead of Flowie's internal `documentId`.\n\nIntegration partners frequently only hold the human-readable invoice number\n(the value on the invoice), not our internal id. This route resolves the\nnumber to exactly one document **scoped to the caller's organization**, then\napplies the *same* transition as `POST /documents/{documentId}/lifecycle` —\nidentical finite-state-machine validation (`ALLOWED_TRANSITIONS`), the same\ntx-docs update, the same PPF/SDI compliance reporting for FR/IT documents,\nand the same `lifecycle.updated` webhook. The request body and success\nresponse are identical to the id-based route.\n\nBecause invoice numbers are **not unique** (the same number can exist as a\nsale and a purchase, or across periods), resolution is strict:\n\n- **0 matches → 404** — no document with that number that your organization\n  is a party on.\n- **exactly 1 match → 200** — the transition is applied.\n- **more than 1 match → 409** — ambiguous; re-issue the call against\n  `POST /documents/{documentId}/lifecycle` with the specific `documentId`.\n\nPayment fields (`paymentDate`, `paymentAmount`, `paymentCurrency`,\n`paymentReference`) are required when `status=paid` or\n`status=partially_paid`, exactly as on the id-based route. Likewise a\n`reasonCode` is required for `rejected` / `disputed` — the 14 official\nPeppol status reason codes are documented at\n<https://docs.get-flowie.com/reference/#reason-codes>.\n\n---\n\n**Example request — approve invoice `INV-2026-0042`:**\n```\nPOST /v1/documents/by-number/INV-2026-0042/lifecycle\n```\n```json\n{\n  \"status\": \"approved\",\n  \"note\": \"Invoice verified against PO\"\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"documentId\": \"doc_test001\",\n  \"previousStatus\": \"received\",\n  \"currentStatus\": \"approved\",\n  \"updatedAt\": \"2026-04-15T10:32:18.421Z\",\n  \"compliance\": {},\n  \"allowedTransitions\": [\"partially_paid\", \"paid\", \"disputed\"]\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `invalid_transition`| Target `status` is not in `ALLOWED_TRANSITIONS` from the current. |\n| 400    | `validation_error`  | Required payment field missing for `paid`/`partially_paid`.       |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 404    | `not_found`         | No document with that invoice number in your organization.        |\n| 409    | `conflict`          | Invoice number matches multiple documents — target by documentId. |\n| 422    | `validation_error`  | Body / path failed schema validation (legacy handler).            |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 502    | `upstream_error`    | tx-docs or compliance platform (PPF/SDI) returned an error.       |\n| 503    | `upstream_unavailable` | tx-docs or compliance platform unreachable / timed out.        |",
        "operationId": "update_lifecycle_by_number_v1_documents_by_number__number__lifecycle_post",
        "parameters": [
          {
            "name": "number",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Number"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LifecycleUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status updated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LifecycleUpdateResponse"
                },
                "example": {
                  "documentId": "doc_test001",
                  "previousStatus": "received",
                  "currentStatus": "approved",
                  "updatedAt": "2026-04-15T10:32:18.421Z",
                  "compliance": {},
                  "allowedTransitions": [
                    "partially_paid",
                    "paid",
                    "disputed"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request — unknown `status`, illegal transition from the current state, or missing required payment fields for `status=paid`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document belongs to another organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream transaction-documents service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream transaction-documents service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "No document with that invoice number in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Multiple documents match this invoice number — target by documentId instead.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/lifecycle/batch": {
      "post": {
        "tags": [
          "Lifecycle"
        ],
        "summary": "Transition many documents in one call",
        "description": "Apply many lifecycle updates in one HTTP round-trip. Each entry in\n`updates` is shaped like the body of `POST /documents/{id}/lifecycle`\nplus a top-level `documentId`. Updates are applied sequentially; a\nfailed transition on one item does not abort the rest.\n\n---\n\n**Example request:**\n```json\n{\n  \"updates\": [\n    {\n      \"documentId\": \"doc_test001\",\n      \"status\": \"approved\",\n      \"note\": \"Invoice verified against PO\"\n    },\n    {\n      \"documentId\": \"doc_test002\",\n      \"status\": \"paid\",\n      \"paymentDate\": \"2026-04-15\",\n      \"paymentAmount\": 4200.00,\n      \"paymentCurrency\": \"EUR\",\n      \"paymentReference\": \"PAY-2026-0043\"\n    }\n  ]\n}\n```\n\n**Example response (200):**\n```json\n[\n  {\n    \"documentId\": \"doc_test001\",\n    \"previousStatus\": \"received\",\n    \"currentStatus\": \"approved\",\n    \"updatedAt\": \"2026-04-15T10:32:18.421Z\",\n    \"compliance\": {},\n    \"allowedTransitions\": [\"partially_paid\", \"paid\", \"disputed\"]\n  },\n  {\n    \"documentId\": \"doc_test002\",\n    \"previousStatus\": \"approved\",\n    \"currentStatus\": \"paid\",\n    \"updatedAt\": \"2026-04-15T10:33:01.117Z\",\n    \"compliance\": {},\n    \"allowedTransitions\": []\n  }\n]\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`   | `updates` empty or contains malformed entries.                    |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | One of the documents belongs to a different organization.         |\n| 422    | `validation_error`  | Body failed schema validation (legacy handler).                   |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 502    | `upstream_error`    | tx-docs or compliance platform returned an error.                 |\n| 503    | `upstream_unavailable` | tx-docs or compliance platform unreachable / timed out.        |",
        "operationId": "batch_lifecycle_update_v1_documents_lifecycle_batch_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchLifecycleUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "List of per-document lifecycle update results, in the same order as the request. Errors on individual items are surfaced inline; the overall call still succeeds.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/LifecycleUpdateResponse"
                  },
                  "title": "Response Batch Lifecycle Update V1 Documents Lifecycle Batch Post"
                },
                "example": [
                  {
                    "documentId": "doc_test001",
                    "previousStatus": "received",
                    "currentStatus": "approved",
                    "updatedAt": "2026-04-15T10:32:18.421Z",
                    "compliance": {},
                    "allowedTransitions": [
                      "partially_paid",
                      "paid",
                      "disputed"
                    ]
                  },
                  {
                    "documentId": "doc_test002",
                    "previousStatus": "approved",
                    "currentStatus": "paid",
                    "updatedAt": "2026-04-15T10:33:01.117Z",
                    "compliance": {},
                    "allowedTransitions": []
                  }
                ]
              }
            }
          },
          "400": {
            "description": "Invalid request — unknown `status`, illegal transition from the current state, or missing required payment fields for `status=paid`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Document belongs to another organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream transaction-documents service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream transaction-documents service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/compliance/status": {
      "get": {
        "tags": [
          "Compliance"
        ],
        "summary": "Per-company compliance posture across registered jurisdictions",
        "description": "Return a compliance snapshot for every company the calling API key owns.\n\nFor each Peppol registration scoped to the caller's organisation, this rolls up the\ncounts of `compliance_report` rows by status (`synced`, `pending`, `failed`, `rejected`)\nand derives an overall `status` per company:\n\n- `compliant` — at least one synced report, no failures / rejections.\n- `pending` — only pending reports, none failed.\n- `non_compliant` — any failed or rejected report.\n- otherwise the raw registration status (e.g. `awaiting_smp`).\n\nUseful as a single-pane dashboard for finance / ops to see which entities are at risk\nacross the regimes the org reports to (PPF, SDI, Peppol-BIS, XRechnung, KSeF, ZATCA, …).\n\n---\n\n**Example request:**\n```\nGET /v1/compliance/status?country=FR\nAuthorization: Bearer flw_live_***\n```\n\n**Example response (200):**\n```json\n{\n  \"companies\": [\n    {\n      \"companyId\": \"comp_abc123\",\n      \"peppolId\": \"0009:921376265\",\n      \"country\": \"FR\",\n      \"status\": \"compliant\",\n      \"smpRegistered\": true,\n      \"smpRegisteredAt\": \"2025-02-10T14:23:11Z\",\n      \"compliance\": {\"synced\": 142, \"pending\": 3, \"failed\": 0, \"rejected\": 0},\n      \"lastCheckedAt\": \"2026-06-17T08:01:42Z\"\n    }\n  ]\n}\n```\n\n**Example response (401):**\n```json\n{\n  \"type\": \"about:blank\",\n  \"code\": \"unauthorized\",\n  \"message\": \"Missing or invalid API key.\",\n  \"details\": [],\n  \"requestId\": \"req_01HZX...\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`     | Unknown country code, malformed `companyId`, conflicting filters.|\n| 401    | `unauthorized`        | Missing / invalid `Authorization` header or API key.            |\n| 403    | `forbidden`           | Key valid but lacks `compliance:read` scope.                    |\n| 422    | `validation_error`    | Query schema validation failed (e.g. `country` not 2 letters).  |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Aggregation failed unexpectedly.                                |\n| 502    | `upstream_error`      | A backing e-invoicing platform returned a non-2xx response.     |\n| 503    | `upstream_unavailable`| Backing compliance platform unreachable / timed out.            |",
        "operationId": "get_compliance_status_v1_compliance_status_get",
        "parameters": [
          {
            "name": "companyId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Restrict the result to a single company / Flowie organisation. Slug-style id, e.g. `comp_abc123`.",
              "examples": [
                "comp_abc123"
              ],
              "title": "Companyid"
            },
            "description": "Restrict the result to a single company / Flowie organisation. Slug-style id, e.g. `comp_abc123`."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 2,
                  "pattern": "^[A-Za-z]{2}$"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO 3166-1 alpha-2 country code (uppercase). Filters both the companies surfaced and the compliance reports counted per jurisdiction. Examples: `FR` (PPF), `IT` (SDI), `BE` (Peppol-BIS), `DE` (XRechnung), `PL` (KSeF), `RO` (e-Factura), `SA` (ZATCA), `IN` (GST-IRP).",
              "examples": [
                "FR",
                "IT",
                "BE",
                "DE",
                "PL"
              ],
              "title": "Country"
            },
            "description": "ISO 3166-1 alpha-2 country code (uppercase). Filters both the companies surfaced and the compliance reports counted per jurisdiction. Examples: `FR` (PPF), `IT` (SDI), `BE` (Peppol-BIS), `DE` (XRechnung), `PL` (KSeF), `RO` (e-Factura), `SA` (ZATCA), `IN` (GST-IRP)."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComplianceStatusResponse"
                },
                "example": {
                  "companies": [
                    {
                      "companyId": "comp_abc123",
                      "vatNumber": "FR26921376265",
                      "peppolId": "0009:921376265",
                      "name": "FLOWIE",
                      "country": "FR",
                      "status": "compliant",
                      "smpRegistered": true,
                      "smpRegisteredAt": "2025-02-10T14:23:11Z",
                      "compliance": {
                        "synced": 142,
                        "pending": 3,
                        "failed": 0,
                        "rejected": 0
                      },
                      "lastCheckedAt": "2026-06-17T08:01:42Z"
                    },
                    {
                      "companyId": "comp_xyz789",
                      "vatNumber": "IT01234567890",
                      "peppolId": "0211:it01234567890",
                      "name": "ACME SRL",
                      "country": "IT",
                      "status": "non_compliant",
                      "smpRegistered": true,
                      "smpRegisteredAt": "2024-09-01T10:00:00Z",
                      "compliance": {
                        "synced": 87,
                        "pending": 1,
                        "failed": 2,
                        "rejected": 1
                      },
                      "lastCheckedAt": "2026-06-17T07:50:11Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters (e.g. unknown country code, malformed date).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while aggregating compliance state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream e-invoicing platform (PPF, SDI, KSeF, ZATCA, …) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream compliance platform unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/compliance/reports": {
      "get": {
        "tags": [
          "Compliance"
        ],
        "summary": "List individual compliance reports (per document) emitted to e-invoicing platforms",
        "description": "List per-document compliance reports filed with external e-invoicing platforms.\n\nEach `ComplianceReport` row represents one submission of a document to one\njurisdictional platform (PPF, SDI, KSeF, ZATCA, e-Factura, …). Records are returned in\nreverse-chronological order on `reportedAt`. Use the `cursor` returned in the previous\npage's last record id to walk pages.\n\nTypical use cases: finance reconciliation (\"which invoices have we successfully reported\nto SDI this month?\"), error triage (\"show me all `failed` reports in PL last week\"), and\naudit trails.\n\n---\n\n**Example request:**\n```\nGET /v1/compliance/reports?country=FR&status=failed&from=2026-06-01T00:00:00Z&limit=50\nAuthorization: Bearer flw_live_***\n```\n\n**Example response (200):**\n```json\n{\n  \"records\": [\n    {\n      \"documentId\": \"doc_01HZXFAILED9876543210\",\n      \"type\": \"invoice\",\n      \"number\": \"INV-2026-0043\",\n      \"issueDate\": \"2026-06-12\",\n      \"status\": \"failed\",\n      \"reportedAt\": \"2026-06-12T09:18:02Z\",\n      \"reportedTo\": \"PPF\",\n      \"platformResponse\": {\"code\": \"PPF-422\", \"message\": \"schema invalid\"},\n      \"error\": \"PPF rejected: missing UBL CustomizationID\"\n    }\n  ]\n}\n```\n\n**Example response (422):**\n```json\n{\n  \"type\": \"about:blank\",\n  \"code\": \"validation_error\",\n  \"message\": \"country must be exactly 2 letters\",\n  \"details\": [{\"field\": \"country\", \"rule\": \"max_length\", \"message\": \"ensure this value has at most 2 characters\"}],\n  \"requestId\": \"req_01HZX...\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`     | Bad date format, unknown country, invalid `status` value.       |\n| 401    | `unauthorized`        | Missing / invalid API key.                                      |\n| 403    | `forbidden`           | Key lacks `compliance:read` scope.                              |\n| 422    | `validation_error`    | Query schema validation failed.                                 |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Query failed unexpectedly.                                      |\n| 502    | `upstream_error`      | Backing platform returned a non-2xx response.                   |\n| 503    | `upstream_unavailable`| Backing platform unreachable / timed out.                       |",
        "operationId": "list_compliance_reports_v1_compliance_reports_get",
        "parameters": [
          {
            "name": "companyId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Restrict to a single company / org id, e.g. `comp_abc123`.",
              "examples": [
                "comp_abc123"
              ],
              "title": "Companyid"
            },
            "description": "Restrict to a single company / org id, e.g. `comp_abc123`."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 2,
                  "pattern": "^[A-Za-z]{2}$"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO 3166-1 alpha-2 country code of the reporting jurisdiction.",
              "examples": [
                "FR",
                "IT",
                "PL",
                "SA"
              ],
              "title": "Country"
            },
            "description": "ISO 3166-1 alpha-2 country code of the reporting jurisdiction."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by report status: `pending`, `synced`, `failed`, `rejected`.",
              "examples": [
                "synced",
                "failed"
              ],
              "title": "Status"
            },
            "description": "Filter by report status: `pending`, `synced`, `failed`, `rejected`."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO 8601 lower bound on `reportedAt` (inclusive). Example: `2026-01-01T00:00:00Z`.",
              "examples": [
                "2026-01-01T00:00:00Z"
              ],
              "title": "From"
            },
            "description": "ISO 8601 lower bound on `reportedAt` (inclusive). Example: `2026-01-01T00:00:00Z`."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO 8601 upper bound on `reportedAt` (inclusive). Example: `2026-06-30T23:59:59Z`.",
              "examples": [
                "2026-06-30T23:59:59Z"
              ],
              "title": "To"
            },
            "description": "ISO 8601 upper bound on `reportedAt` (inclusive). Example: `2026-06-30T23:59:59Z`."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Maximum number of records to return (1–100).",
              "default": 20,
              "title": "Limit"
            },
            "description": "Maximum number of records to return (1–100)."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Opaque pagination cursor — pass the last record's id from the previous page.",
              "examples": [
                "rpt_01HZXABCDEF0123456789"
              ],
              "title": "Cursor"
            },
            "description": "Opaque pagination cursor — pass the last record's id from the previous page."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComplianceReportResponse"
                },
                "example": {
                  "records": [
                    {
                      "documentId": "doc_01HZXABCDEF0123456789",
                      "type": "invoice",
                      "number": "INV-2026-0042",
                      "issueDate": "2026-06-12",
                      "status": "synced",
                      "reportedAt": "2026-06-12T09:15:33Z",
                      "reportedTo": "PPF",
                      "platformResponse": {
                        "ackId": "PPF-ACK-7741",
                        "receivedAt": "2026-06-12T09:15:34Z"
                      }
                    },
                    {
                      "documentId": "doc_01HZXFAILED9876543210",
                      "type": "invoice",
                      "number": "INV-2026-0043",
                      "issueDate": "2026-06-12",
                      "status": "failed",
                      "reportedAt": "2026-06-12T09:18:02Z",
                      "reportedTo": "SDI",
                      "platformResponse": {
                        "code": "00400",
                        "message": "Invalid VAT"
                      },
                      "error": "SDI rejected: invalid recipient VAT"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters (e.g. unknown country code, malformed date).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while aggregating compliance state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream e-invoicing platform (PPF, SDI, KSeF, ZATCA, …) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream compliance platform unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/directory/search": {
      "get": {
        "tags": [
          "Directory"
        ],
        "summary": "Search the Peppol directory and the French PPF annuaire",
        "description": "Search the Peppol Directory + French PPF annuaire.\n\nResolution order:\n  1. **PPF annuaire** (French companies) — exact SIREN/SIRET lookup via `vatNumber` or\n     `q`, then a name search when `country=FR`.\n  2. **Peppol Directory** (international) — `directory.peppol.eu` with the standard\n     `q / participant / country / city / zip / naics / doctype` filters.\n  3. **Local registrations** fallback (Flowie-managed Peppol participants) — only when\n     neither `q` nor `vatNumber` is supplied, to avoid leaking unrelated rows.\n\nYou must supply at least one search criterion (`q`, `vatNumber`, or `country`), and a\nfree-text `q` must be scoped by `country` (a bare SIREN/SIRET or `vatNumber` is exempt).\nResults are collapsed to one row per legal entity unless `includeSubEntities=true`.\n\n---\n\n**Example — search by name (Peppol Directory):**\n```\nGET /v1/directory/search?q=Vodafone&country=GB&limit=5\n```\n```json\n{\n  \"data\": [\n    {\n      \"peppolId\": \"9932:gb569953277\",\n      \"name\": \"VODAFONE GROUP SERVICES LIMITED\",\n      \"country\": \"GB\",\n      \"city\": null,\n      \"postalCode\": null,\n      \"vatNumber\": null,\n      \"registeredSince\": \"2022-02-10T00:00:00\",\n      \"documentTypes\": [\"invoice\", \"credit-note\"],\n      \"accessPoint\": null\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n**Example — French SIREN lookup (PPF annuaire):**\n```\nGET /v1/directory/search?q=921376265&country=FR\n```\n```json\n{\n  \"data\": [\n    {\n      \"peppolId\": \"0009:921376265\",\n      \"name\": \"FLOWIE\",\n      \"country\": \"FR\",\n      \"city\": \"PARIS\",\n      \"postalCode\": \"75008\",\n      \"vatNumber\": \"FR26921376265\",\n      \"registeredSince\": null,\n      \"documentTypes\": [\"invoice\", \"credit-note\"],\n      \"accessPoint\": \"PDP-0001\"\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n**Example — filter by sector (NACE):**\n```\nGET /v1/directory/search?country=FR&naceCodes=62.01&limit=10\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                          | When                                                              |\n|--------|-------------------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`             | Malformed VAT, unknown country code, conflicting filters.         |\n| 401    | `unauthorized`                | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`                   | Key valid but lacks `directory:read`, or wrong org.               |\n| 422    | `validation_error`            | Query schema validation failed (e.g. `country` not 2 letters).    |\n| 429    | `rate_limited`                | Too many requests — retry after `Retry-After` seconds.            |\n| 502    | `upstream_error`              | Peppol Directory or ppf-annuaire returned a non-2xx response.     |\n| 503    | `upstream_unavailable`        | Peppol Directory or ppf-annuaire unreachable / timed out.         |",
        "operationId": "search_directory_v1_directory_search_get",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Free-text query. Matched as a **company / business name** against the Peppol Directory; for French results the PPF annuaire name index is also queried. If the value is a bare 9-digit SIREN or 14-digit SIRET it is routed directly to the French identifier lookup. Whitespace, dots and dashes inside the value are stripped before the digit test. One of `q` or `vatNumber` is required.",
              "examples": [
                "Vodafone",
                "FLOWIE",
                "921376265",
                "92137626500017"
              ],
              "title": "Q"
            },
            "description": "Free-text query. Matched as a **company / business name** against the Peppol Directory; for French results the PPF annuaire name index is also queried. If the value is a bare 9-digit SIREN or 14-digit SIRET it is routed directly to the French identifier lookup. Whitespace, dots and dashes inside the value are stripped before the digit test. One of `q` or `vatNumber` is required."
          },
          {
            "name": "vatNumber",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "EU VAT identification number, optionally prefixed by the 2-letter ISO 3166-1 country code (e.g. `FR26921376265`, `BE0123456789`). For French VATs the SIREN is extracted (trailing 9 digits) and matched against the PPF annuaire; for other countries the value is forwarded to the Peppol Directory `participant` filter. One of `q` or `vatNumber` is required.",
              "examples": [
                "FR26921376265",
                "BE0123456789"
              ],
              "title": "Vatnumber"
            },
            "description": "EU VAT identification number, optionally prefixed by the 2-letter ISO 3166-1 country code (e.g. `FR26921376265`, `BE0123456789`). For French VATs the SIREN is extracted (trailing 9 digits) and matched against the PPF annuaire; for other countries the value is forwarded to the Peppol Directory `participant` filter. One of `q` or `vatNumber` is required."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 2,
                  "pattern": "^[A-Za-z]{2}$"
                },
                {
                  "type": "null"
                }
              ],
              "description": "**ISO 3166-1 alpha-2** country code (uppercase, 2 letters — `FR`, `BE`, `DE`, `GB`, …). Selects the directory backend: `FR` triggers the PPF annuaire path, everything else hits the Peppol Directory only. **Required when searching by a free-text `q`** (a bare SIREN/SIRET or a `vatNumber` already carries its country, so it is exempt).",
              "examples": [
                "FR",
                "BE",
                "GB"
              ],
              "title": "Country"
            },
            "description": "**ISO 3166-1 alpha-2** country code (uppercase, 2 letters — `FR`, `BE`, `DE`, `GB`, …). Selects the directory backend: `FR` triggers the PPF annuaire path, everything else hits the Peppol Directory only. **Required when searching by a free-text `q`** (a bare SIREN/SIRET or a `vatNumber` already carries its country, so it is exempt)."
          },
          {
            "name": "city",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "City name — forwarded as-is to the Peppol Directory `city` filter.",
              "examples": [
                "Paris"
              ],
              "title": "City"
            },
            "description": "City name — forwarded as-is to the Peppol Directory `city` filter."
          },
          {
            "name": "postalCode",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Postal / ZIP code — forwarded to the Peppol Directory `zip` filter.",
              "examples": [
                "75001"
              ],
              "title": "Postalcode"
            },
            "description": "Postal / ZIP code — forwarded to the Peppol Directory `zip` filter."
          },
          {
            "name": "naceCodes",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "**NACE** = *Nomenclature statistique des Activités économiques dans la Communauté Européenne* — the EU statistical classification of economic activities (Regulation (EC) No 1893/2006). Pass one or more dot-formatted codes (e.g. `62.01` = *Computer programming activities*, `47.11` = *Retail sale in non-specialised stores*). Multiple codes are comma-separated. Forwarded to the Peppol Directory `naics` filter.",
              "examples": [
                "62.01",
                "62.01,62.02"
              ],
              "title": "Nacecodes"
            },
            "description": "**NACE** = *Nomenclature statistique des Activités économiques dans la Communauté Européenne* — the EU statistical classification of economic activities (Regulation (EC) No 1893/2006). Pass one or more dot-formatted codes (e.g. `62.01` = *Computer programming activities*, `47.11` = *Retail sale in non-specialised stores*). Multiple codes are comma-separated. Forwarded to the Peppol Directory `naics` filter."
          },
          {
            "name": "documentTypes",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Comma-separated list of Peppol document-type identifiers / UBL URNs that the recipient must support (e.g. `invoice`, `credit-note`, or a full `busdox-docid-qns::urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##…` URN). Forwarded to the Peppol Directory `doctype` filter.",
              "examples": [
                "invoice",
                "invoice,credit-note"
              ],
              "title": "Documenttypes"
            },
            "description": "Comma-separated list of Peppol document-type identifiers / UBL URNs that the recipient must support (e.g. `invoice`, `credit-note`, or a full `busdox-docid-qns::urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##…` URN). Forwarded to the Peppol Directory `doctype` filter."
          },
          {
            "name": "includeSubEntities",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "description": "When `false` (default) results are collapsed to **one row per legal entity** — the directory lists each company once per identifier scheme (national + VAT). Set `true` to return every identifier-scheme / establishment row, e.g. when you need the exact routable participant ID.",
              "default": false,
              "title": "Includesubentities"
            },
            "description": "When `false` (default) results are collapsed to **one row per legal entity** — the directory lists each company once per identifier scheme (national + VAT). Set `true` to return every identifier-scheme / establishment row, e.g. when you need the exact routable participant ID."
          },
          {
            "name": "detail",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^(basic|full)$",
              "description": "`basic` (default) returns directory fields only. `full` enriches each row with access-point / SMP detail — slower, as it issues one lookup per result.",
              "examples": [
                "basic",
                "full"
              ],
              "default": "basic",
              "title": "Detail"
            },
            "description": "`basic` (default) returns directory fields only. `full` enriches each row with access-point / SMP detail — slower, as it issues one lookup per result."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Maximum number of distinct results to return (1–100).",
              "default": 20,
              "title": "Limit"
            },
            "description": "Maximum number of distinct results to return (1–100)."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_DirectorySearchResult_"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters (e.g. malformed VAT, unknown country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream directory (Peppol Directory / ppf-annuaire) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream directory unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/directory/{peppol_id}": {
      "get": {
        "tags": [
          "Directory"
        ],
        "summary": "Look up a single Peppol participant by ID",
        "description": "Resolve a Peppol ID (`<scheme>:<identifier>`, e.g. `0009:921376265` for a French\nSIREN, `0208:0123456789` for a Belgian CBE) against local registrations → PPF annuaire\n(French only) → Peppol Directory. Returns 404 if no source has the participant.",
        "operationId": "lookup_peppol_id_v1_directory__peppol_id__get",
        "parameters": [
          {
            "name": "peppol_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Peppol Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryLookupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters (e.g. malformed VAT, unknown country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream directory (Peppol Directory / ppf-annuaire) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream directory unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Peppol participant not found in any backing directory.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/directory/verify": {
      "post": {
        "tags": [
          "Directory"
        ],
        "summary": "Verify a Peppol recipient can receive a given document type",
        "description": "Check that `peppolId` is registered AND advertises support for `documentType`\n(matched substring-wise against the participant's SMP `canReceive` capabilities).",
        "operationId": "verify_recipient_v1_directory_verify_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters (e.g. malformed VAT, unknown country code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream directory (Peppol Directory / ppf-annuaire) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream directory unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/partners": {
      "post": {
        "tags": [
          "Partners"
        ],
        "summary": "Create a partner (supplier / buyer / both)",
        "description": "Register a new partner (trading counterparty) in the caller's organization.\n\nA partner is a counterparty you exchange invoices / documents with through Peppol.\nAt least one of `peppolId` or `vatNumber` must be supplied — Flowie derives the\nother where possible. Sending an `Idempotency-Key` header replays the original\nresponse if the same key is reused within the retention window.\n\n**Example request:**\n```http\nPOST /v1/partners\nIdempotency-Key: 0e8f1d4c-1c0e-4f8e-9a3a-2b9d11e2f5b7\nContent-Type: application/json\n\n{\n  \"peppolId\": \"0009:BE0123456789\",\n  \"vatNumber\": \"BE0123456789\",\n  \"role\": \"supplier\",\n  \"contactName\": \"Jean Dupont\",\n  \"contactEmail\": \"jean@example.com\",\n  \"tags\": [\"preferred\"]\n}\n```\n\n**Example response (201):**\n```json\n{\n  \"id\": \"part_abc123\",\n  \"peppolId\": \"0009:BE0123456789\",\n  \"name\": \"Acme BVBA\",\n  \"vatNumber\": \"BE0123456789\",\n  \"country\": \"BE\",\n  \"role\": \"supplier\",\n  \"contactName\": \"Jean Dupont\",\n  \"contactEmail\": \"jean@example.com\",\n  \"peppolStatus\": \"active\",\n  \"tags\": [\"preferred\"]\n}\n```\n\n**Example error (400 — no identifier):**\n```json\n{\n  \"type\": \"invalid_request\",\n  \"code\": \"missing_identifier\",\n  \"message\": \"At least one of peppolId or vatNumber must be provided\",\n  \"details\": [],\n  \"requestId\": \"req_01HX...\"\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                 | When                                                              |\n|--------|----------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`    | Neither `peppolId` nor `vatNumber` given, or VAT malformed.       |\n| 401    | `unauthorized`       | Missing / invalid API key.                                        |\n| 403    | `forbidden`          | Key lacks `partners:write`.                                       |\n| 422    | `validation_error`   | Body failed schema validation (e.g. bad email pattern).           |\n| 429    | `rate_limited`       | Too many requests — retry after `Retry-After` seconds.            |\n| 502    | `upstream_error`     | BOR / org-v2 returned a non-2xx response.                         |\n| 503    | `upstream_unavailable` | BOR / org-v2 unreachable or timed out.                          |",
        "operationId": "create_partner_v1_partners_post",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Idempotency-Key"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PartnerCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Partner created (or replayed via Idempotency-Key).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerResponse"
                },
                "example": {
                  "id": "part_abc123",
                  "peppolId": "0009:BE0123456789",
                  "name": "Acme BVBA",
                  "vatNumber": "BE0123456789",
                  "country": "BE",
                  "role": "supplier",
                  "contactName": "Jean Dupont",
                  "contactEmail": "jean@example.com",
                  "peppolStatus": "active",
                  "tags": [
                    "preferred"
                  ],
                  "createdAt": "2026-01-12T10:23:11Z",
                  "updatedAt": "2026-03-04T08:15:00Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing identifier).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (book-of-relations / org-v2) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (book-of-relations / org-v2) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Partners"
        ],
        "summary": "List partners (union of book-of-relations + org-v2 partnerships)",
        "description": "List the caller's partners.\n\nThe page is a deduped union of two upstream sources — book-of-relations (BOR) and\norg-v2 partnerships — with BOR rows winning ties on `id`. The cursor is an opaque\noffset; pass the value returned by the previous page to get the next.\n\n**Example request:**\n```http\nGET /v1/partners?role=supplier&country=BE&limit=20\n```\n\n**Example response (200):**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"part_abc123\",\n      \"peppolId\": \"0009:BE0123456789\",\n      \"name\": \"Acme BVBA\",\n      \"country\": \"BE\",\n      \"role\": \"supplier\",\n      \"peppolStatus\": \"active\",\n      \"tags\": [\"preferred\"]\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | Unsupported `sortBy` / `order`, bad cursor format.            |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `partners:read`.                                    |\n| 422    | `validation_error`     | Query failed schema validation.                               |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | BOR / org-v2 returned a non-2xx response.                     |\n| 503    | `upstream_unavailable` | BOR / org-v2 unreachable or timed out.                        |",
        "operationId": "list_partners_v1_partners_get",
        "parameters": [
          {
            "name": "role",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Role"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Search"
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Country"
            }
          },
          {
            "name": "tags",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Tags"
            }
          },
          {
            "name": "hasActivity",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Hasactivity"
            }
          },
          {
            "name": "peppolStatus",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Peppolstatus"
            }
          },
          {
            "name": "sortBy",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Sortby"
            }
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Order"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "title": "Limit"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deduped paginated list of the caller's partners.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_PartnerListItem_"
                },
                "example": {
                  "data": [
                    {
                      "id": "part_abc123",
                      "peppolId": "0009:BE0123456789",
                      "name": "Acme BVBA",
                      "country": "BE",
                      "role": "supplier",
                      "peppolStatus": "active",
                      "tags": [
                        "preferred"
                      ],
                      "stats": {
                        "lastAction": "2026-03-04T08:15:00Z"
                      }
                    },
                    {
                      "id": "part_def456",
                      "peppolId": "0009:921376265",
                      "name": "FLOWIE",
                      "country": "FR",
                      "role": "buyer",
                      "peppolStatus": "active",
                      "tags": []
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing identifier).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (book-of-relations / org-v2) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (book-of-relations / org-v2) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/partners/by-account-number": {
      "get": {
        "tags": [
          "Partners"
        ],
        "summary": "Resolve a partner by an internal account number (custom field)",
        "description": "Reverse lookup: find the partner (org) linked to a customer account whose\ninternal account number is stored as a custom field.\n\nThe `value` is matched against custom-field rows scoped to your organization;\nthe matched object is then resolved to the partner. Returns 404 when no\npartner matches.",
        "operationId": "get_partner_by_account_number_v1_partners_by_account_number_get",
        "parameters": [
          {
            "name": "value",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The exact custom-field value to match, e.g. an internal customer/account number.",
              "title": "Value"
            },
            "description": "The exact custom-field value to match, e.g. an internal customer/account number."
          },
          {
            "name": "field",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Name of the custom-field definition holding the account number.",
              "default": "Numéro de compte interne",
              "title": "Field"
            },
            "description": "Name of the custom-field definition holding the account number."
          },
          {
            "name": "entityType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Entity type the custom field is attached to.",
              "default": "PARTNERSHIP",
              "title": "Entitytype"
            },
            "description": "Entity type the custom field is attached to."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The partner whose custom field matches the value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerResponse"
                },
                "example": {
                  "id": "part_abc123",
                  "peppolId": "0009:BE0123456789",
                  "name": "Acme BVBA",
                  "vatNumber": "BE0123456789",
                  "country": "BE",
                  "role": "supplier",
                  "contactName": "Jean Dupont",
                  "contactEmail": "jean@example.com",
                  "peppolStatus": "active",
                  "tags": [
                    "preferred"
                  ],
                  "createdAt": "2026-01-12T10:23:11Z",
                  "updatedAt": "2026-03-04T08:15:00Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing identifier).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (book-of-relations / org-v2) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (book-of-relations / org-v2) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Partner not found in book-of-relations nor in org-v2 partnerships.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/partners/{partner_id}/invoices": {
      "get": {
        "tags": [
          "Partners"
        ],
        "summary": "List invoices exchanged with a partner",
        "description": "List every invoice exchanged between your organization and this partner\n(the partner as seller or payer). Scoped to your org by the platform.",
        "operationId": "list_partner_invoices_v1_partners__partner_id__invoices_get",
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Partner Id"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Limit"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Opaque pagination cursor from the previous page.",
              "title": "Cursor"
            },
            "description": "Opaque pagination cursor from the previous page."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoices between your org and this partner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_DocumentListItem_"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing identifier).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (book-of-relations / org-v2) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (book-of-relations / org-v2) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/partners/{partner_id}": {
      "get": {
        "tags": [
          "Partners"
        ],
        "summary": "Get a partner by id, `vat:<VAT>`, or `peppol:<scheme:id>`",
        "description": "Fetch a partner by its Flowie id, or by `vat:<VAT>` / `peppol:<scheme:id>` alias.\n\nThe path parameter accepts three forms — `part_abc123`, `vat:BE0123456789`, or\n`peppol:0009:BE0123456789`. The service tries BOR first, then falls back to org-v2\npartnerships.\n\n**Example request:**\n```http\nGET /v1/partners/vat:BE0123456789\n```\n\n**Example response (200):** see the example body above.\n\n**Example error (404):**\n```json\n{\n  \"type\": \"not_found\",\n  \"code\": \"partner_not_found\",\n  \"message\": \"No partner matches 'vat:BE0123456789' in this organization.\",\n  \"details\": [],\n  \"requestId\": \"req_01HX...\"\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | Identifier prefix malformed.                                  |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `partners:read`.                                    |\n| 404    | `partner_not_found`    | No matching partner in BOR or org-v2.                         |\n| 422    | `validation_error`     | Path validation failed.                                       |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | BOR / org-v2 returned a non-2xx response.                     |\n| 503    | `upstream_unavailable` | BOR / org-v2 unreachable or timed out.                        |",
        "operationId": "get_partner_v1_partners__partner_id__get",
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Partner Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full partner profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerResponse"
                },
                "example": {
                  "id": "part_abc123",
                  "peppolId": "0009:BE0123456789",
                  "name": "Acme BVBA",
                  "vatNumber": "BE0123456789",
                  "country": "BE",
                  "role": "supplier",
                  "contactName": "Jean Dupont",
                  "contactEmail": "jean@example.com",
                  "peppolStatus": "active",
                  "tags": [
                    "preferred"
                  ],
                  "createdAt": "2026-01-12T10:23:11Z",
                  "updatedAt": "2026-03-04T08:15:00Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing identifier).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (book-of-relations / org-v2) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (book-of-relations / org-v2) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Partner not found in book-of-relations nor in org-v2 partnerships.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Partners"
        ],
        "summary": "Update a partner (partial / JSON merge-patch semantics)",
        "description": "Partially update a partner. Only fields present in the body are touched.\n\nNested dict fields (`defaults`, `metadata`) are shallow-merged with the existing\nvalue; pass an explicit `null` to clear a field.\n\n**Example request:**\n```http\nPATCH /v1/partners/part_abc123\nContent-Type: application/json\n\n{\n  \"tags\": [\"preferred\", \"vip\"],\n  \"contactEmail\": \"billing@acme.example\"\n}\n```\n\n**Example response (200):** the updated partner — see body above.\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 400    | `invalid_request`      | Malformed field value (e.g. bad email).                       |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `partners:write`.                                   |\n| 404    | `partner_not_found`    | No matching partner.                                          |\n| 422    | `validation_error`     | Body failed schema validation.                                |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | BOR / org-v2 returned a non-2xx response.                     |\n| 503    | `upstream_unavailable` | BOR / org-v2 unreachable or timed out.                        |",
        "operationId": "update_partner_v1_partners__partner_id__patch",
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Partner Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PartnerUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated partner profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartnerResponse"
                },
                "example": {
                  "id": "part_abc123",
                  "peppolId": "0009:BE0123456789",
                  "name": "Acme BVBA",
                  "vatNumber": "BE0123456789",
                  "country": "BE",
                  "role": "supplier",
                  "contactName": "Jean Dupont",
                  "contactEmail": "jean@example.com",
                  "peppolStatus": "active",
                  "tags": [
                    "preferred",
                    "vip"
                  ],
                  "createdAt": "2026-01-12T10:23:11Z",
                  "updatedAt": "2026-03-04T08:15:00Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing identifier).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (book-of-relations / org-v2) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (book-of-relations / org-v2) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Partner not found in book-of-relations nor in org-v2 partnerships.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Partners"
        ],
        "summary": "Delete a partner",
        "description": "Permanently delete a partner from the caller's organization.\n\nReturns `204 No Content` on success. Already-deleted partners return `404`\nso the operation is *not* idempotent — callers should treat a 404 after a\nsuccessful prior delete as a no-op.\n\n**Example request:**\n```http\nDELETE /v1/partners/part_abc123\n```\n\n**Errors** (body follows `ErrorResponse` except for 204):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 204    | —                      | Partner deleted (no body).                                    |\n| 400    | `invalid_request`      | Identifier prefix malformed.                                  |\n| 401    | `unauthorized`         | Missing / invalid API key.                                    |\n| 403    | `forbidden`            | Key lacks `partners:write`.                                   |\n| 404    | `partner_not_found`    | No matching partner.                                          |\n| 422    | `validation_error`     | Path validation failed.                                       |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | BOR / org-v2 returned a non-2xx response.                     |\n| 503    | `upstream_unavailable` | BOR / org-v2 unreachable or timed out.                        |",
        "operationId": "delete_partner_v1_partners__partner_id__delete",
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Partner Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Partner deleted (no body)."
          },
          "400": {
            "description": "Malformed request (e.g. invalid VAT, missing identifier).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (book-of-relations / org-v2) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (book-of-relations / org-v2) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Partner not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/purchase-orders/{purchase_order_id}/invoices": {
      "get": {
        "tags": [
          "Purchase Orders"
        ],
        "summary": "List invoices linked to a purchase order",
        "description": "List every invoice linked to the given purchase order. Scoped to your\norganization by the platform (you must be a party on the documents).",
        "operationId": "list_purchase_order_invoices_v1_purchase_orders__purchase_order_id__invoices_get",
        "parameters": [
          {
            "name": "purchase_order_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Purchase Order Id"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Limit"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Opaque pagination cursor from the previous page.",
              "title": "Cursor"
            },
            "description": "Opaque pagination cursor from the previous page."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoices linked to this purchase order.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_DocumentListItem_"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks the required scope for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream (transaction-documents) returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream (transaction-documents) unavailable or timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Register a new webhook endpoint",
        "description": "Register an HTTPS endpoint to receive event notifications.\n\nThe webhook is bound to the caller's organization (and optionally a single\n`companyId`). If `secret` is omitted, the server generates a 64-hex-character\nsigning secret and uses it for HMAC-SHA256 signatures via the\n`X-Flowie-Signature` header on each delivery. The secret is NEVER returned\nin any response — store it client-side at create time if you want it.\n\n---\n\n**Example request:**\n```json\n{\n  \"url\": \"https://example.com/webhooks/peppol\",\n  \"events\": [\"document.received\", \"document.delivered\"],\n  \"secret\": \"whsec_abc123\"\n}\n```\n\n**Example response (201):**\n```json\n{\n  \"id\": \"wh_01HF8K3JD9V2M8X7Q9N3R4T5Y6\",\n  \"url\": \"https://example.com/webhooks/peppol\",\n  \"events\": [\"document.received\", \"document.delivered\"],\n  \"status\": \"active\",\n  \"companyId\": \"comp_abc123\",\n  \"createdAt\": \"2026-04-15T10:32:18Z\",\n  \"lastDeliveredAt\": null,\n  \"failureCount\": 0\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `validation_error`  | `url` missing, not http(s), `events` list empty.                  |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Key lacks the `webhooks.write` scope.                             |\n| 422    | `validation_error`  | Body failed schema validation (legacy handler).                   |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected error while persisting the webhook.                    |",
        "operationId": "create_webhook_v1_webhooks_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook successfully registered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookResponse"
                },
                "example": {
                  "id": "wh_01HF8K3JD9V2M8X7Q9N3R4T5Y6",
                  "url": "https://example.com/webhooks/peppol",
                  "events": [
                    "document.received",
                    "document.delivered"
                  ],
                  "status": "active",
                  "companyId": "comp_abc123",
                  "createdAt": "2026-04-15T10:32:18Z",
                  "failureCount": 0
                }
              }
            }
          },
          "400": {
            "description": "Validation error (e.g. missing `url`, empty `events`, non-http(s) URL).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required `webhooks.read` / `webhooks.write` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while persisting the webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhooks registered for the caller's organization",
        "description": "List all webhooks the API key can see.\n\nFor a personal/platform key bound to a single company, results are\nscoped to that company. For a white-label / org-wide key, every webhook\nin the organization is returned — pass `companyId` to narrow the view.\n\n---\n\n**Example response (200):**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"wh_01HF8K3JD9V2M8X7Q9N3R4T5Y6\",\n      \"url\": \"https://example.com/webhooks/peppol\",\n      \"events\": [\"document.received\", \"document.delivered\"],\n      \"status\": \"active\",\n      \"companyId\": \"comp_abc123\",\n      \"createdAt\": \"2026-04-15T10:32:18Z\",\n      \"lastDeliveredAt\": \"2026-04-16T08:11:02Z\",\n      \"failureCount\": 0\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `validation_error`  | Query parameter is malformed.                                     |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Key lacks the `webhooks.read` scope.                              |\n| 422    | `validation_error`  | Query failed schema validation (legacy handler).                  |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected error while reading webhooks from the DB.              |",
        "operationId": "list_webhooks_v1_webhooks_get",
        "parameters": [
          {
            "name": "companyId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Companyid"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of registered webhooks (currently un-paginated — `hasMore` is always `false`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_WebhookResponse_"
                },
                "example": {
                  "data": [
                    {
                      "id": "wh_01HF8K3JD9V2M8X7Q9N3R4T5Y6",
                      "url": "https://example.com/webhooks/peppol",
                      "events": [
                        "document.received",
                        "document.delivered"
                      ],
                      "status": "active",
                      "companyId": "comp_abc123",
                      "createdAt": "2026-04-15T10:32:18Z",
                      "failureCount": 0
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "400": {
            "description": "Validation error (e.g. missing `url`, empty `events`, non-http(s) URL).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required `webhooks.read` / `webhooks.write` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while persisting the webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{webhook_id}": {
      "patch": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Update a webhook's URL, event list, or signing secret",
        "description": "Partially update a webhook. Only the fields provided in the body are\nchanged. Pass `rotateSecret: true` to mint a new 64-hex-character signing\nsecret — the new secret is generated server-side and is NOT returned, so\nout-of-band sharing is required to keep verifying signatures.\n\n---\n\n**Example request:**\n```json\n{\n  \"events\": [\"document.received\", \"document.delivered\", \"document.failed\"],\n  \"rotateSecret\": true\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"id\": \"wh_01HF8K3JD9V2M8X7Q9N3R4T5Y6\",\n  \"url\": \"https://example.com/webhooks/peppol\",\n  \"events\": [\"document.received\", \"document.delivered\", \"document.failed\"],\n  \"status\": \"active\",\n  \"companyId\": \"comp_abc123\",\n  \"createdAt\": \"2026-04-15T10:32:18Z\",\n  \"lastDeliveredAt\": \"2026-04-16T08:11:02Z\",\n  \"failureCount\": 0\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `validation_error`  | Invalid URL or event list.                                        |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Key lacks the `webhooks.write` scope.                             |\n| 404    | `not_found`         | No webhook with that id in the caller's organization.             |\n| 422    | `validation_error`  | Body failed schema validation (legacy handler).                   |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected error while persisting the change.                     |",
        "operationId": "update_webhook_v1_webhooks__webhook_id__patch",
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Webhook Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook successfully updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookResponse"
                },
                "example": {
                  "id": "wh_01HF8K3JD9V2M8X7Q9N3R4T5Y6",
                  "url": "https://example.com/webhooks/peppol",
                  "events": [
                    "document.received",
                    "document.delivered"
                  ],
                  "status": "active",
                  "companyId": "comp_abc123",
                  "createdAt": "2026-04-15T10:32:18Z",
                  "failureCount": 0
                }
              }
            }
          },
          "400": {
            "description": "Validation error (e.g. missing `url`, empty `events`, non-http(s) URL).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required `webhooks.read` / `webhooks.write` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while persisting the webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Webhook not found, or belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete a webhook subscription",
        "description": "Permanently delete a webhook. Idempotent against re-delete: a second\ncall against the same id returns 404. In-flight retries for prior deliveries\nare NOT cancelled — they continue until their backoff schedule is exhausted.\n\n---\n\n**Example request:**\n```\nDELETE /v1/webhooks/wh_01HF8K3JD9V2M8X7Q9N3R4T5Y6\n```\n\nReturns `204 No Content` on success.\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Key lacks the `webhooks.write` scope.                             |\n| 404    | `not_found`         | No webhook with that id in the caller's organization.             |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Unexpected error while deleting from the DB.                      |",
        "operationId": "delete_webhook_v1_webhooks__webhook_id__delete",
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Webhook Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Webhook deleted. No response body."
          },
          "400": {
            "description": "Validation error (e.g. missing `url`, empty `events`, non-http(s) URL).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required `webhooks.read` / `webhooks.write` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while persisting the webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Webhook not found, or belongs to a different organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/events": {
      "get": {
        "tags": [
          "Events"
        ],
        "summary": "List unacknowledged events for the caller's organization",
        "description": "List events the caller has not yet acknowledged.\n\nEvents represent observable things that happened to your documents\n(`document.received`, `document.sent`, `document.delivered`,\n`document.failed`, `lifecycle.updated`, …) — they are the persistent\ncounterpart to webhook deliveries, available to clients who poll\ninstead of (or in addition to) subscribing to webhooks.\n\nCursor-based pagination over `(createdAt, id)` — pass the `cursor` from\na previous page to fetch the next one. `hasMore=false` means you've\nreached the end. Personal/platform keys see only their bound company;\norg-wide keys default to their own organization and may narrow with\n`companyId` — but only to a company/organization the key can access. A\n`companyId` outside the caller's tenant returns `403`, never another\ntenant's events.\n\n---\n\n**Example response (200):**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"evt_5e8c9a1f3b7d4a2c9e1f8b3d7a2c9e1f\",\n      \"type\": \"document.received\",\n      \"createdAt\": \"2026-04-15T10:32:18.421Z\",\n      \"data\": {\n        \"documentId\": \"doc_test001\",\n        \"direction\": \"incoming\",\n        \"number\": \"INV-2026-0042\",\n        \"from\": \"0009:FR86797978996\",\n        \"to\": \"0208:0123456789\"\n      }\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`   | `cursor` refers to an event that no longer exists.                |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Key has no read access to the requested company.                  |\n| 422    | `validation_error`  | Query failed schema validation (e.g. non-int `limit`).            |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | DB error while reading events.                                    |",
        "operationId": "list_events_v1_events_get",
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Type"
            }
          },
          {
            "name": "companyId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Companyid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "title": "Limit"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of unacknowledged events, ordered oldest-first by (createdAt, id).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_EventResponse_"
                },
                "example": {
                  "data": [
                    {
                      "id": "evt_5e8c9a1f3b7d4a2c9e1f8b3d7a2c9e1f",
                      "type": "document.received",
                      "createdAt": "2026-04-15T10:32:18.421Z",
                      "data": {
                        "documentId": "doc_test001",
                        "direction": "incoming",
                        "number": "INV-2026-0042",
                        "from": "0009:FR86797978996",
                        "to": "0208:0123456789"
                      }
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters (e.g. malformed `cursor`, unknown `type`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key cannot access this event / company.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while reading the event store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/events/{event_id}/ack": {
      "post": {
        "tags": [
          "Events"
        ],
        "summary": "Acknowledge a single event so it stops appearing in /v1/events",
        "description": "Mark a single event as acknowledged. Acknowledged events no longer\nappear in `GET /v1/events`. The call is idempotent — acknowledging\nan already-acknowledged event is a no-op success.\n\n---\n\n**Example request:**\n```\nPOST /v1/events/evt_5e8c9a1f3b7d4a2c9e1f8b3d7a2c9e1f/ack\n```\n\nReturns `204 No Content` on success.\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Event belongs to a different company than the key allows.         |\n| 404    | `not_found`         | No event with that id in the store.                               |\n| 422    | `validation_error`  | Path id failed schema validation.                                 |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | DB error while updating the event row.                            |",
        "operationId": "ack_event_v1_events__event_id__ack_post",
        "parameters": [
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Event Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Event acknowledged. No response body."
          },
          "400": {
            "description": "Invalid query parameters (e.g. malformed `cursor`, unknown `type`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key cannot access this event / company.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while reading the event store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Event id not found in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/events/ack": {
      "post": {
        "tags": [
          "Events"
        ],
        "summary": "Acknowledge a batch of events in a single call",
        "description": "Acknowledge many events at once. All ids must belong to the caller's\norganization (and bound company if the key is scoped) — the call is\nrejected as a whole if any id is missing or forbidden.\n\n---\n\n**Example request:**\n```json\n{\n  \"eventIds\": [\n    \"evt_5e8c9a1f3b7d4a2c9e1f8b3d7a2c9e1f\",\n    \"evt_71b3c8e4d9a2f5c8e1b3d7a2c9e1f8b3\"\n  ]\n}\n```\n\nReturns `204 No Content` on success.\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`   | `eventIds` empty or malformed.                                    |\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | At least one event belongs to a different company.                |\n| 404    | `not_found`         | At least one event id does not exist.                             |\n| 422    | `validation_error`  | Body failed schema validation (legacy handler).                   |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | DB error while updating events.                                   |",
        "operationId": "batch_ack_events_v1_events_ack_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AckRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "All listed events acknowledged. No response body."
          },
          "400": {
            "description": "Invalid query parameters (e.g. malformed `cursor`, unknown `type`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key cannot access this event / company.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while reading the event store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Event id not found in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/events/{event_id}/replay": {
      "post": {
        "tags": [
          "Events"
        ],
        "summary": "Re-deliver a previously emitted event to subscribed webhooks",
        "description": "Re-deliver a previously emitted event to all matching webhooks.\n\nUse this to recover from a downstream outage on your side: the original\nJSON payload is preserved byte-for-byte; only the `X-Flowie-Delivery`\nid and the `X-Flowie-Signature` timestamp differ from the first\ndelivery, so HMAC signature verification still succeeds with your\nexisting webhook secret. Returns a summary\n`{eventId, found, matched, delivered, deliveryId}` describing how many\nsubscribed endpoints were attempted and how many accepted the call.\n\n---\n\n**Example response (200):**\n```json\n{\n  \"eventId\": \"evt_5e8c9a1f3b7d4a2c9e1f8b3d7a2c9e1f\",\n  \"found\": true,\n  \"matched\": 2,\n  \"delivered\": 2,\n  \"deliveryId\": \"dlv_01HF8K3JD9V2M8X7Q9N3R4T5Y6\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                | When                                                              |\n|--------|---------------------|-------------------------------------------------------------------|\n| 401    | `unauthorized`      | Missing / invalid `Authorization` header or API key.              |\n| 403    | `forbidden`         | Event belongs to a different company than the key allows.         |\n| 404    | `not_found`         | Event id does not exist (or was purged).                          |\n| 422    | `validation_error`  | Path id failed schema validation.                                 |\n| 429    | `rate_limited`      | Too many requests — retry after `Retry-After` seconds.            |\n| 500    | `internal_error`    | Failure while dispatching to webhooks.                            |",
        "operationId": "replay_event_v1_events__event_id__replay_post",
        "parameters": [
          {
            "name": "event_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Event Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Replay attempt summary.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Replay Event V1 Events  Event Id  Replay Post"
                },
                "example": {
                  "eventId": "evt_5e8c9a1f3b7d4a2c9e1f8b3d7a2c9e1f",
                  "found": true,
                  "matched": 2,
                  "delivered": 2,
                  "deliveryId": "dlv_01HF8K3JD9V2M8X7Q9N3R4T5Y6"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters (e.g. malformed `cursor`, unknown `type`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key cannot access this event / company.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while reading the event store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Event id not found in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stats": {
      "get": {
        "tags": [
          "Stats"
        ],
        "summary": "Usage, quota, and rate-limit stats for the calling API key",
        "description": "Return aggregated usage and limits for the API key's organisation, for a given month.\n\nCombines three pieces of information that consumers need on a single dashboard:\n\n1. **Quota** — documents-sent + documents-received counted against the tier limit\n   (from `QUOTAS`). `unlimited: true` is returned for enterprise tiers without a cap.\n2. **Rate limit** — requests-per-minute ceiling enforced on this key (the key-level\n   override wins over the tier default from `RATE_LIMITS`).\n3. **Documents** — granular counts of sent / received / failed / total for the period.\n\nUseful for billing dashboards, in-app meters, and as the data source for the\n`usage.quota_warning` webhook event.\n\n---\n\n**Example request:**\n```\nGET /v1/stats?period=2026-06\nAuthorization: Bearer flw_live_***\n```\n\n**Example response (200):**\n```json\n{\n  \"period\": {\"value\": \"2026-06\", \"start\": \"2026-06-01T00:00:00Z\"},\n  \"quota\": {\"used\": 1247, \"limit\": 10000, \"unlimited\": false, \"percentUsed\": 12.5},\n  \"rateLimit\": {\"requestsPerMinute\": 600},\n  \"documents\": {\"sent\": 812, \"received\": 435, \"failed\": 4, \"total\": 1247},\n  \"byType\": null,\n  \"byCountry\": null,\n  \"partners\": null\n}\n```\n\n**Example response (200, enterprise tier):**\n```json\n{\n  \"period\": {\"value\": \"2026-06\", \"start\": \"2026-06-01T00:00:00Z\"},\n  \"quota\": {\"used\": 184230, \"limit\": null, \"unlimited\": true, \"percentUsed\": null},\n  \"rateLimit\": {\"requestsPerMinute\": 6000},\n  \"documents\": {\"sent\": 120410, \"received\": 63820, \"failed\": 12, \"total\": 184230},\n  \"byType\": null,\n  \"byCountry\": null,\n  \"partners\": null\n}\n```\n\n**Example response (422):**\n```json\n{\n  \"type\": \"about:blank\",\n  \"code\": \"validation_error\",\n  \"message\": \"period must match ^\\d{4}-\\d{2}$\",\n  \"details\": [{\"field\": \"period\", \"rule\": \"pattern\", \"message\": \"string does not match pattern\"}],\n  \"requestId\": \"req_01HZX...\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`     | Period not parseable as `YYYY-MM`, or unknown `companyId`.      |\n| 401    | `unauthorized`        | Missing / invalid `Authorization` header or API key.            |\n| 403    | `forbidden`           | Key valid but lacks `stats:read` (or wrong org).                |\n| 422    | `validation_error`    | Query schema validation failed.                                 |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Aggregation failed unexpectedly.                                |",
        "operationId": "get_stats_v1_stats_get",
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "pattern": "^\\d{4}-\\d{2}$"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Monthly billing period in `YYYY-MM` form (UTC). Defaults to the current month when omitted. Historical periods are accepted as long as `usage_record` rows exist.",
              "examples": [
                "2026-06",
                "2026-05"
              ],
              "title": "Period"
            },
            "description": "Monthly billing period in `YYYY-MM` form (UTC). Defaults to the current month when omitted. Historical periods are accepted as long as `usage_record` rows exist."
          },
          {
            "name": "companyId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Optional company / organisation scope. When supplied alongside an API key bound to a specific company, restricts the aggregation to that company's usage rows. Slug-style id.",
              "examples": [
                "comp_abc123"
              ],
              "title": "Companyid"
            },
            "description": "Optional company / organisation scope. When supplied alongside an API key bound to a specific company, restricts the aggregation to that company's usage rows. Slug-style id."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatsResponse"
                },
                "example": {
                  "period": {
                    "value": "2026-06",
                    "start": "2026-06-01T00:00:00Z"
                  },
                  "quota": {
                    "used": 1247,
                    "limit": 10000,
                    "unlimited": false,
                    "percentUsed": 12.5
                  },
                  "rateLimit": {
                    "requestsPerMinute": 600
                  },
                  "documents": {
                    "sent": 812,
                    "received": 435,
                    "failed": 4,
                    "total": 1247
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters (e.g. malformed `period`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while aggregating usage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/platform/companies": {
      "post": {
        "tags": [
          "Platform"
        ],
        "summary": "Onboard a managed company (create org + optional webhook + key)",
        "description": "One-call onboarding for a company the platform manages on behalf of an end\ncustomer. Creates the company in org-v2, optionally provisions a webhook,\nand optionally mints an API key bound to that company — all atomically from\nthe caller's point of view. Requires a `platform` or `white_label` key with\nthe `companies.write` scope.\n\n---\n\n**Example request:**\n```bash\ncurl -X POST https://api.flowie.fr/v1/platform/companies \\\n  -H \"Authorization: Bearer flw_plat_live_…\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"vatNumber\": \"FR02779658772\",\n    \"name\": \"HOZELOCK EXEL\",\n    \"receiveDocuments\": true,\n    \"autoVerify\": false,\n    \"webhook\": {\n      \"url\": \"https://customer.example.com/webhooks/peppol\",\n      \"events\": [\"document.received\", \"document.delivered\"]\n    },\n    \"apiKey\": {\n      \"name\": \"HOZELOCK production key\",\n      \"scopes\": [\"documents.read\", \"documents.write\"],\n      \"tier\": \"starter\"\n    }\n  }'\n```\n\n**Example 201 response:**\n```json\n{\n  \"company\": {\n    \"id\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n    \"vatNumber\": \"FR02779658772\",\n    \"name\": \"HOZELOCK EXEL\",\n    \"country\": \"FR\",\n    \"peppolId\": \"0009:02779658772\",\n    \"status\": \"active\",\n    \"smpRegistered\": true\n  },\n  \"apiKey\": {\n    \"id\": \"key_8f2c41a3b6e84d119f5a3c2b9a7d6e1f\",\n    \"key\": \"flw_live_8f2c41a3b6e84d119f5a3c2b9a7d6e1f7a2c5b8d3e9f0a1b\",\n    \"keyPrefix\": \"flw_live_8f2c\"\n  },\n  \"webhook\": {\n    \"id\": \"wh_abc123\",\n    \"url\": \"https://customer.example.com/webhooks/peppol\",\n    \"events\": [\"document.received\", \"document.delivered\"],\n    \"status\": \"active\"\n  }\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                 | When                                                                |\n|--------|----------------------|---------------------------------------------------------------------|\n| 400    | `invalid_request`    | Malformed `vatNumber`, blank `apiKey.name`, etc.                    |\n| 401    | `unauthorized`       | Missing / invalid `Authorization` header.                           |\n| 403    | `forbidden_key_type` | Caller is not a `platform` / `white_label` key, or missing scope.   |\n| 422    | `validation_error`   | Body failed Pydantic validation.                                    |\n| 429    | `rate_limited`       | Too many requests — retry after `Retry-After`.                      |\n| 502    | `upstream_error`     | org-v2 rejected the create call.                                    |\n| 503    | `upstream_unavailable` | org-v2 unreachable / timed out.                                   |",
        "operationId": "onboard_company_v1_platform_companies_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlatformOnboardRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Managed company created. The optional `apiKey.key` field is the only chance to capture the secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlatformOnboardResponse"
                },
                "example": {
                  "company": {
                    "id": "019a6e5b-3960-7000-ab88-153aed5a6240",
                    "organizationId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                    "name": "HOZELOCK EXEL",
                    "vatNumber": "FR02779658772",
                    "country": "FR",
                    "peppolId": "0009:02779658772",
                    "status": "active",
                    "smpRegistered": true,
                    "createdAt": "2026-06-17T09:14:22.157894Z"
                  },
                  "apiKey": {
                    "id": "key_8f2c41a3b6e84d119f5a3c2b9a7d6e1f",
                    "key": "flw_live_8f2c41a3b6e84d119f5a3c2b9a7d6e1f7a2c5b8d3e9f0a1b",
                    "keyPrefix": "flw_live_8f2c"
                  },
                  "webhook": {
                    "id": "wh_abc123",
                    "url": "https://customer.example.com/webhooks/peppol",
                    "events": [
                      "document.received",
                      "document.delivered"
                    ],
                    "status": "active",
                    "failureCount": 0
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. malformed VAT, missing required field, conflicting filters).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not a `platform` or `white_label` key, or the targeted `companyId` is not a company managed by this platform.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (org-v2 / Sovos) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unreachable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Platform"
        ],
        "summary": "List the companies managed by this platform",
        "description": "Return every company in this platform's org-v2 ownership graph (its child\norganizations). Requires a `platform` or `white_label` key with the\n`companies.read` scope. In sandbox mode an empty page is returned — sandbox\nplatform tenants don't have real child orgs in org-v2.\n\n---\n\n**Example response:**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n      \"name\": \"HOZELOCK EXEL\",\n      \"vatNumber\": \"FR02779658772\",\n      \"country\": \"FR\",\n      \"peppolId\": \"0009:02779658772\",\n      \"status\": \"active\",\n      \"stats\": {\"documentsSent\": 142, \"documentsReceived\": 87}\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                       |\n|--------|------------------------|------------------------------------------------------------|\n| 401    | `unauthorized`         | Missing / invalid `Authorization` header.                  |\n| 403    | `forbidden_key_type`   | Caller is not a `platform` / `white_label` key.            |\n| 429    | `rate_limited`         | Too many requests — retry after `Retry-After`.             |\n| 502    | `upstream_error`       | org-v2 returned a non-2xx response.                        |\n| 503    | `upstream_unavailable` | org-v2 unreachable / timed out.                            |",
        "operationId": "list_managed_companies_v1_platform_companies_get",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of managed (org-v2 child) companies. Empty list in sandbox.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_CompanyListItem_"
                },
                "example": {
                  "data": [
                    {
                      "id": "019a6e5b-3960-7000-ab88-153aed5a6240",
                      "name": "HOZELOCK EXEL",
                      "vatNumber": "FR02779658772",
                      "country": "FR",
                      "peppolId": "0009:02779658772",
                      "status": "active",
                      "stats": {
                        "documentsSent": 142,
                        "documentsReceived": 87
                      }
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. malformed VAT, missing required field, conflicting filters).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not a `platform` or `white_label` key, or the targeted `companyId` is not a company managed by this platform.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (org-v2 / Sovos) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unreachable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/platform/api-keys": {
      "post": {
        "tags": [
          "Platform"
        ],
        "summary": "Mint an API key for a managed company",
        "description": "Mint an API key on behalf of a managed company. Requires a `platform` or\n`white_label` key, the `api_keys.write` scope, and a `companyId` belonging\nto a company this platform manages — otherwise returns `403`.\n\nFor keys on your *own* organization, use the self-service endpoint\n`POST /v1/api-keys` instead.\n\n---\n\n**Example request:**\n```bash\ncurl -X POST https://api.flowie.fr/v1/platform/api-keys \\\n  -H \"Authorization: Bearer flw_plat_live_…\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"companyId\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n    \"name\": \"HOZELOCK production key\",\n    \"scopes\": [\"documents.read\", \"documents.write\"]\n  }'\n```\n\n**Example 201 response:**\n```json\n{\n  \"id\": \"key_3b81e0d2f74a4c9b8e1f6a5d2c8b9a3e\",\n  \"key\": \"flw_live_3b81e0d2f74a4c9b8e1f6a5d2c8b9a3e9c2a4b6d8f1e3a5c\",\n  \"keyPrefix\": \"flw_live_3b81\",\n  \"name\": \"HOZELOCK production key\",\n  \"scopes\": [\"documents.read\", \"documents.write\"],\n  \"companyId\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n  \"createdAt\": \"2026-06-17T09:14:22.157894Z\",\n  \"expiresAt\": null\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                              |\n|--------|-----------------------|-------------------------------------------------------------------|\n| 400    | `invalid_request`     | Missing `companyId` (required for platform keys), past `expiresAt`. |\n| 401    | `unauthorized`        | Missing / invalid `Authorization` header.                         |\n| 403    | `forbidden_key_type`  | Caller is not a `platform` / `white_label` key.                   |\n| 403    | `company_unmanaged`   | `companyId` is not one of this platform's managed companies.      |\n| 403    | `scope_escalation`    | Requested scopes exceed the caller's own scopes.                  |\n| 422    | `validation_error`    | Body failed Pydantic validation (e.g. blank `name`).              |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After`.                    |",
        "operationId": "create_api_key_v1_platform_api_keys_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiKeyCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Key minted. The `key` field is the full secret — store it now, it will not be shown again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreateResponse"
                },
                "example": {
                  "id": "key_3b81e0d2f74a4c9b8e1f6a5d2c8b9a3e",
                  "key": "flw_live_3b81e0d2f74a4c9b8e1f6a5d2c8b9a3e9c2a4b6d8f1e3a5c",
                  "keyPrefix": "flw_live_3b81",
                  "name": "HOZELOCK production key",
                  "scopes": [
                    "documents.read",
                    "documents.write"
                  ],
                  "companyId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "createdAt": "2026-06-17T09:14:22.157894Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. malformed VAT, missing required field, conflicting filters).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not a `platform` or `white_label` key, or the targeted `companyId` is not a company managed by this platform.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (org-v2 / Sovos) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unreachable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Platform"
        ],
        "summary": "List API keys issued to managed companies",
        "description": "List the API keys currently issued to companies this platform manages\n(i.e. keys carrying a `companyId`). Requires a `platform` or `white_label`\nkey with the `api_keys.read` scope. Pass `companyId` to scope down to one\nmanaged tenant. For keys on your own org, use `GET /v1/api-keys`.\n\n---\n\n**Example response:**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"key_3b81e0d2f74a4c9b8e1f6a5d2c8b9a3e\",\n      \"keyPrefix\": \"flw_live_3b81\",\n      \"name\": \"HOZELOCK production key\",\n      \"scopes\": [\"documents.read\", \"documents.write\"],\n      \"companyId\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n      \"createdAt\": \"2026-04-12T08:00:00Z\",\n      \"expiresAt\": null\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                  |\n|--------|-----------------------|-------------------------------------------------------|\n| 401    | `unauthorized`        | Missing / invalid `Authorization` header.             |\n| 403    | `forbidden_key_type`  | Caller is not a `platform` / `white_label` key.       |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After`.        |",
        "operationId": "list_api_keys_v1_platform_api_keys_get",
        "parameters": [
          {
            "name": "companyId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter results to a single managed company id.",
              "examples": [
                "019a6e5b-3960-7000-ab88-153aed5a6240"
              ],
              "title": "Companyid"
            },
            "description": "Filter results to a single managed company id."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Non-revoked keys belonging to managed companies (filter via `companyId`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_ApiKeyResponse_"
                },
                "example": {
                  "data": [
                    {
                      "id": "key_3b81e0d2f74a4c9b8e1f6a5d2c8b9a3e",
                      "keyPrefix": "flw_live_3b81",
                      "name": "HOZELOCK production key",
                      "scopes": [
                        "documents.read",
                        "documents.write"
                      ],
                      "companyId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                      "createdAt": "2026-04-12T08:00:00Z"
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. malformed VAT, missing required field, conflicting filters).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not a `platform` or `white_label` key, or the targeted `companyId` is not a company managed by this platform.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (org-v2 / Sovos) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unreachable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/platform/api-keys/{key_id}": {
      "delete": {
        "tags": [
          "Platform"
        ],
        "summary": "Revoke a managed-company API key",
        "description": "Revoke a key previously issued under one of the platform's managed\ncompanies. Requires a `platform` or `white_label` key. Revocation is a\nsoft-delete: the key row is kept (audit trail) but `is_revoked=true` —\nfurther auth attempts return `401 unauthorized`.\n\n---\n\n**Example request:**\n```bash\ncurl -X DELETE https://api.flowie.fr/v1/platform/api-keys/key_3b81e0d2f74a4c9b8e1f6a5d2c8b9a3e \\\n  -H \"Authorization: Bearer flw_plat_live_…\"\n```\n\nReturns `204 No Content` — no body.\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                  |\n|--------|-----------------------|-------------------------------------------------------|\n| 401    | `unauthorized`        | Missing / invalid `Authorization` header.             |\n| 403    | `forbidden_key_type`  | Caller is not a `platform` / `white_label` key.       |\n| 404    | `not_found`           | Key id does not exist under this platform's org.      |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After`.        |",
        "operationId": "revoke_api_key_v1_platform_api_keys__key_id__delete",
        "parameters": [
          {
            "name": "key_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Key Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Key revoked — subsequent requests using it will return 401."
          },
          "400": {
            "description": "Invalid request payload (e.g. malformed VAT, missing required field, conflicting filters).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not a `platform` or `white_label` key, or the targeted `companyId` is not a company managed by this platform.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (org-v2 / Sovos) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unreachable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "No API key with that id exists under the platform's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/platform/usage": {
      "get": {
        "tags": [
          "Platform"
        ],
        "summary": "Aggregate platform usage for a billing period",
        "description": "Return aggregated document / API counters for the platform's organization\nover a billing period. Requires a `platform` or `white_label` key with the\n`usage.read` scope. Use `groupBy=company` to surface a per-managed-company\nbreakdown (handy for fan-out billing).\n\n---\n\n**Example request:**\n```\nGET /v1/platform/usage?period=2026-06&groupBy=company\n```\n\n**Example response:**\n```json\n{\n  \"period\": {\"value\": \"2026-06\"},\n  \"total\": {\n    \"documentsSent\": 5421,\n    \"documentsReceived\": 3187,\n    \"documentsFailed\": 12,\n    \"apiCalls\": 184230\n  },\n  \"byCompany\": [\n    {\n      \"apiKeyId\": \"key_3b81e0d2f74a4c9b8e1f6a5d2c8b9a3e\",\n      \"documentsSent\": 2103,\n      \"documentsReceived\": 1542,\n      \"documentsFailed\": 4,\n      \"apiCalls\": 71204\n    }\n  ]\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                  |\n|--------|-----------------------|-------------------------------------------------------|\n| 400    | `invalid_request`     | `period` not in `YYYY-MM` form.                       |\n| 401    | `unauthorized`        | Missing / invalid `Authorization` header.             |\n| 403    | `forbidden_key_type`  | Caller is not a `platform` / `white_label` key.       |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After`.        |",
        "operationId": "get_usage_v1_platform_usage_get",
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Billing period in `YYYY-MM` form. Defaults to the current calendar month (UTC).",
              "examples": [
                "2026-06"
              ],
              "title": "Period"
            },
            "description": "Billing period in `YYYY-MM` form. Defaults to the current calendar month (UTC)."
          },
          {
            "name": "groupBy",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Set to `company` to break totals down per managed company (returned in `byCompany`).",
              "examples": [
                "company"
              ],
              "title": "Groupby"
            },
            "description": "Set to `company` to break totals down per managed company (returned in `byCompany`)."
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregated counters; `byCompany` populated only when `groupBy=company`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlatformUsageResponse"
                },
                "example": {
                  "period": {
                    "value": "2026-06"
                  },
                  "total": {
                    "documentsSent": 5421,
                    "documentsReceived": 3187,
                    "documentsFailed": 12,
                    "apiCalls": 184230
                  },
                  "byCompany": [
                    {
                      "apiKeyId": "key_3b81e0d2f74a4c9b8e1f6a5d2c8b9a3e",
                      "documentsSent": 2103,
                      "documentsReceived": 1542,
                      "documentsFailed": 4,
                      "apiCalls": 71204
                    },
                    {
                      "apiKeyId": "key_8f2c41a3b6e84d119f5a3c2b9a7d6e1f",
                      "documentsSent": 3318,
                      "documentsReceived": 1645,
                      "documentsFailed": 8,
                      "apiCalls": 113026
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. malformed VAT, missing required field, conflicting filters).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not a `platform` or `white_label` key, or the targeted `companyId` is not a company managed by this platform.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (org-v2 / Sovos) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unreachable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/platform/events": {
      "get": {
        "tags": [
          "Platform"
        ],
        "summary": "Stream every event across the platform's managed companies",
        "description": "Return the unified event stream for *every* company managed by this\nplatform — useful as a fallback when an integrator's webhook receiver is\ndown, or for nightly reconciliation jobs. Requires a `platform` or\n`white_label` key with the `events.read` scope.\n\nDefaults to the most recent 100 events. Use the `cursor` returned in the\nresponse to paginate older entries (cursor-based pagination, opaque token).\n\n---\n\n**Example response:**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"evt_01HFTQ4M5XW8C2A3B4D5E6F7G8\",\n      \"type\": \"document.delivered\",\n      \"createdAt\": \"2026-06-17T09:14:22.157894Z\",\n      \"data\": {\n        \"documentId\": \"doc_01HFTQ4M5XW8C2A3B4D5E6F7G8\",\n        \"companyId\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n        \"recipientPeppolId\": \"0208:0123456789\"\n      }\n    }\n  ],\n  \"hasMore\": true,\n  \"cursor\": \"evt_01HFTQ4M5XW8C2A3B4D5E6F7G8\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                  |\n|--------|-----------------------|-------------------------------------------------------|\n| 401    | `unauthorized`        | Missing / invalid `Authorization` header.             |\n| 403    | `forbidden_key_type`  | Caller is not a `platform` / `white_label` key.       |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After`.        |",
        "operationId": "get_platform_events_v1_platform_events_get",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of events emitted across every company managed by this platform.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_EventResponse_"
                },
                "example": {
                  "data": [
                    {
                      "id": "evt_01HFTQ4M5XW8C2A3B4D5E6F7G8",
                      "type": "document.delivered",
                      "createdAt": "2026-06-17T09:14:22.157894Z",
                      "data": {
                        "documentId": "doc_01HFTQ4M5XW8C2A3B4D5E6F7G8",
                        "companyId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                        "recipientPeppolId": "0208:0123456789"
                      }
                    }
                  ],
                  "hasMore": true,
                  "cursor": "evt_01HFTQ4M5XW8C2A3B4D5E6F7G8"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. malformed VAT, missing required field, conflicting filters).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not a `platform` or `white_label` key, or the targeted `companyId` is not a company managed by this platform.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (org-v2 / Sovos) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unreachable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/platform/settings": {
      "patch": {
        "tags": [
          "Platform"
        ],
        "summary": "Update platform branding, defaults, and custom domain",
        "description": "Persist platform-level configuration — branding (logo, colors, email\nfrom-name), per-company defaults (tier, webhook events), and an optional\ncustom CNAME for the white-label dashboard. Requires a `platform` or\n`white_label` key with the `settings.write` scope.\n\n`branding` and `defaults` are **merged** with whatever is already stored —\nkeys you omit are preserved. `customDomain` is a straight replace.\nIn sandbox the body is echoed back without persistence.\n\n---\n\n**Example request:**\n```bash\ncurl -X PATCH https://api.flowie.fr/v1/platform/settings \\\n  -H \"Authorization: Bearer flw_plat_live_…\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"branding\": {\"primaryColor\": \"#1A73E8\"},\n    \"defaults\": {\"tier\": \"starter\"},\n    \"customDomain\": \"peppol.acme-platform.com\"\n  }'\n```\n\n**Example response:**\n```json\n{\n  \"branding\": {\n    \"logoUrl\": \"https://cdn.example.com/logo.svg\",\n    \"primaryColor\": \"#1A73E8\"\n  },\n  \"defaults\": {\"tier\": \"starter\"},\n  \"customDomain\": \"peppol.acme-platform.com\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                  |\n|--------|-----------------------|-------------------------------------------------------|\n| 400    | `invalid_request`     | Malformed `customDomain` (not a hostname).            |\n| 401    | `unauthorized`        | Missing / invalid `Authorization` header.             |\n| 403    | `forbidden_key_type`  | Caller is not a `platform` / `white_label` key.       |\n| 422    | `validation_error`    | Body failed Pydantic validation.                      |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After`.        |\n| 500    | `internal_error`      | Database error while writing `PlatformConfig`.        |",
        "operationId": "update_platform_settings_v1_platform_settings_patch",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlatformSettingsUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Merged settings — branding/defaults are merged with the existing row, `customDomain` replaces.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlatformSettingsUpdate"
                },
                "example": {
                  "branding": {
                    "logoUrl": "https://cdn.example.com/logo.svg",
                    "primaryColor": "#1A73E8",
                    "emailFromName": "Acme Platform"
                  },
                  "defaults": {
                    "tier": "starter",
                    "webhook": {
                      "events": [
                        "document.received",
                        "document.delivered"
                      ]
                    }
                  },
                  "customDomain": "peppol.acme-platform.com"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. malformed VAT, missing required field, conflicting filters).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not a `platform` or `white_label` key, or the targeted `companyId` is not a company managed by this platform.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (org-v2 / Sovos) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unreachable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/api-keys": {
      "post": {
        "tags": [
          "API Keys"
        ],
        "summary": "Create an API key for your own organization",
        "description": "Mint a new API key bound to the caller's organization and tier.\n\nAvailable to any authenticated principal (JWT user or another API key).\nThe new key inherits the caller's organization and tier, and is **scope-clamped**\nto the caller's own scopes — a key holding `documents.read` cannot mint a\nkey with `documents.write`. Pass `expiresAt` to issue a short-lived key\n(must be in the future); pass `rateLimit.requestsPerMinute` to lower the\nkey's rate limit below the tier ceiling.\n\n---\n\n**Example request:**\n```bash\ncurl -X POST https://api.flowie.fr/v1/api-keys \\\n  -H \"Authorization: Bearer flw_live_…\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"CI deploy key\",\n    \"scopes\": [\"documents.read\", \"documents.write\"],\n    \"expiresAt\": \"2027-06-17T09:14:22Z\"\n  }'\n```\n\n**Example 201 response:**\n```json\n{\n  \"id\": \"key_8f2c41a3b6e84d119f5a3c2b9a7d6e1f\",\n  \"key\": \"flw_live_8f2c41a3b6e84d119f5a3c2b9a7d6e1f7a2c5b8d3e9f0a1b\",\n  \"keyPrefix\": \"flw_live_8f2c\",\n  \"name\": \"CI deploy key\",\n  \"scopes\": [\"documents.read\", \"documents.write\"],\n  \"companyId\": null,\n  \"createdAt\": \"2026-06-17T09:14:22.157894Z\",\n  \"expiresAt\": \"2027-06-17T09:14:22.157894Z\"\n}\n```\n\n**Example 403 response — scope escalation blocked:**\n```json\n{\n  \"type\": \"forbidden\",\n  \"code\": \"scope_escalation\",\n  \"message\": \"Cannot grant scopes the caller does not hold: ['documents.write']\",\n  \"details\": [],\n  \"requestId\": \"req_01HF…\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                                 |\n|--------|-----------------------|----------------------------------------------------------------------|\n| 400    | `invalid_request`     | `expiresAt` in the past or malformed `rateLimit`.                    |\n| 401    | `unauthorized`        | Missing / invalid `Authorization` header.                            |\n| 403    | `scope_escalation`    | Requested scopes exceed the caller's own scopes.                     |\n| 422    | `validation_error`    | Body failed Pydantic validation (e.g. blank `name`).                 |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.               |\n| 500    | `internal_error`      | Persistence layer error while saving the new key.                    |",
        "operationId": "create_api_key_v1_api_keys_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiKeyCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Key minted. The `key` field is the full secret — store it now, it will not be shown again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreateResponse"
                },
                "example": {
                  "id": "key_8f2c41a3b6e84d119f5a3c2b9a7d6e1f",
                  "key": "flw_live_8f2c41a3b6e84d119f5a3c2b9a7d6e1f7a2c5b8d3e9f0a1b",
                  "keyPrefix": "flw_live_8f2c",
                  "name": "CI deploy key",
                  "scopes": [
                    "documents.read",
                    "documents.write"
                  ],
                  "createdAt": "2026-06-17T09:14:22.157894Z",
                  "expiresAt": "2027-06-17T09:14:22.157894Z"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request — e.g. `expiresAt` set to a past timestamp, or `rateLimit.requestsPerMinute` not a positive integer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller tried to grant scopes it does not itself hold. New keys are scope-clamped to the caller's own scopes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while persisting the key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "API Keys"
        ],
        "summary": "List API keys for your own organization",
        "description": "List every non-revoked API key in the caller's organization.\n\nReturns the keys' metadata only — the raw secret is **never** returned\nafter creation. The `keyPrefix` (first 12–16 characters) is enough to\ncorrelate a logged request back to a specific key for audit/rotation\nworkflows.\n\n---\n\n**Example response:**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"key_8f2c41a3b6e84d119f5a3c2b9a7d6e1f\",\n      \"keyPrefix\": \"flw_live_8f2c\",\n      \"name\": \"CI deploy key\",\n      \"scopes\": [\"documents.read\", \"documents.write\"],\n      \"companyId\": null,\n      \"createdAt\": \"2026-06-17T09:14:22.157894Z\",\n      \"expiresAt\": \"2027-06-17T09:14:22.157894Z\"\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code              | When                                                  |\n|--------|-------------------|-------------------------------------------------------|\n| 401    | `unauthorized`    | Missing / invalid `Authorization` header.             |\n| 403    | `forbidden`       | Key valid but lacks read access to its own org.       |\n| 429    | `rate_limited`    | Too many requests — retry after `Retry-After`.        |\n| 500    | `internal_error`  | Database error while reading the key table.           |",
        "operationId": "list_api_keys_v1_api_keys_get",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of non-revoked keys belonging to the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_ApiKeyResponse_"
                },
                "example": {
                  "data": [
                    {
                      "id": "key_8f2c41a3b6e84d119f5a3c2b9a7d6e1f",
                      "keyPrefix": "flw_live_8f2c",
                      "name": "CI deploy key",
                      "scopes": [
                        "documents.read",
                        "documents.write"
                      ],
                      "createdAt": "2026-06-17T09:14:22.157894Z",
                      "expiresAt": "2027-06-17T09:14:22.157894Z"
                    },
                    {
                      "id": "key_3b81e0d2f74a4c9b8e1f6a5d2c8b9a3e",
                      "keyPrefix": "flw_test_3b81e0d2",
                      "name": "Local dev",
                      "scopes": [
                        "*"
                      ],
                      "companyId": "comp_abc123",
                      "createdAt": "2026-05-02T11:08:45.000000Z"
                    }
                  ],
                  "hasMore": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid request — e.g. `expiresAt` set to a past timestamp, or `rateLimit.requestsPerMinute` not a positive integer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller tried to grant scopes it does not itself hold. New keys are scope-clamped to the caller's own scopes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while persisting the key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/api-keys/{key_id}": {
      "delete": {
        "tags": [
          "API Keys"
        ],
        "summary": "Revoke an API key by id",
        "description": "Revoke an API key permanently. The key remains in the database (audit\ntrail) but is marked `is_revoked=true`, so any future request presenting\nits secret will fail authentication with `401 unauthorized`.\n\nRevocation is **idempotent** in sandbox/test-mode: revoking a key that\ndoes not exist returns 204 (so test runs that recreate keys don't flake).\nIn live mode, an unknown `key_id` returns `404 not_found`.\n\n---\n\n**Example request:**\n```bash\ncurl -X DELETE https://api.flowie.fr/v1/api-keys/key_8f2c41a3b6e84d119f5a3c2b9a7d6e1f \\\n  -H \"Authorization: Bearer flw_live_…\"\n```\n\nReturns `204 No Content` on success — no body.\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code              | When                                                  |\n|--------|-------------------|-------------------------------------------------------|\n| 401    | `unauthorized`    | Missing / invalid `Authorization` header.             |\n| 403    | `forbidden`       | Caller cannot revoke keys it doesn't own.             |\n| 404    | `not_found`       | No key with that id in the caller's org (live mode).  |\n| 429    | `rate_limited`    | Too many requests — retry after `Retry-After`.        |\n| 500    | `internal_error`  | Database error while updating the key row.            |",
        "operationId": "revoke_api_key_v1_api_keys__key_id__delete",
        "parameters": [
          {
            "name": "key_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Key Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Key revoked — subsequent requests using it will return 401."
          },
          "400": {
            "description": "Invalid request — e.g. `expiresAt` set to a past timestamp, or `rateLimit.requestsPerMinute` not a positive integer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Caller tried to grant scopes it does not itself hold. New keys are scope-clamped to the caller's own scopes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while persisting the key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "No API key with that id exists in the caller's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/categorization/groups": {
      "get": {
        "tags": [
          "Categorization"
        ],
        "summary": "List available tag groups (UNSPSC, Accounting, Custom, …)",
        "description": "List the tag groups available to the calling organisation.\n\nA *tag group* is a category schema — e.g. `UNSPSC` (United Nations Standard Products\nand Services Code, used for procurement classification), `Accounting` (revenue / COGS\n/ opex buckets), or a user-defined `Custom` group. Each group hosts a flat list of\n`Tag` values that can then be assigned to documents, partners, suppliers, etc.\n\nDelegates to the internal Flowie tag service (`TAGS_URL`). Sandbox API keys get a\nsynthetic three-group stub so the contract is exercisable without depending on the\nlive service.\n\n---\n\n**Example request:**\n```\nGET /v1/categorization/groups\nAuthorization: Bearer flw_live_***\n```\n\n**Example response (200):**\n```json\n[\n  {\"id\": \"grp_unspsc\",     \"name\": \"UNSPSC\",     \"code\": \"unspsc\",     \"kind\": \"system\"},\n  {\"id\": \"grp_accounting\", \"name\": \"Accounting\", \"code\": \"accounting\", \"kind\": \"system\"},\n  {\"id\": \"grp_custom\",     \"name\": \"Custom\",     \"code\": \"custom\",     \"kind\": \"user\"}\n]\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`     | Malformed request.                                              |\n| 401    | `unauthorized`        | Missing / invalid API key.                                      |\n| 403    | `forbidden`           | Key lacks `categorization:read` scope.                          |\n| 422    | `validation_error`    | Request failed schema validation.                               |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Internal failure while contacting the tag service.              |\n| 502    | `upstream_error`      | Upstream tag service returned a non-2xx response.               |\n| 503    | `upstream_unavailable`| Upstream tag service unreachable / timed out.                   |",
        "operationId": "list_groups_v1_categorization_groups_get",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {},
                "example": [
                  {
                    "id": "grp_unspsc",
                    "name": "UNSPSC",
                    "code": "unspsc",
                    "kind": "system"
                  },
                  {
                    "id": "grp_accounting",
                    "name": "Accounting",
                    "code": "accounting",
                    "kind": "system"
                  },
                  {
                    "id": "grp_custom",
                    "name": "Custom",
                    "code": "custom",
                    "kind": "user"
                  }
                ]
              }
            }
          },
          "400": {
            "description": "Malformed request body or path parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream tag service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream tag service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/categorization/groups/{group_id}/tags": {
      "get": {
        "tags": [
          "Categorization"
        ],
        "summary": "List the tags (category values) inside a group",
        "description": "List every tag belonging to a given group.\n\n`group_id` is the id returned by `GET /v1/categorization/groups` (e.g.\n`grp_unspsc`). An empty list is returned for groups that simply have no tags yet —\nno 404 — matching the upstream tag-service contract.\n\n---\n\n**Example request:**\n```\nGET /v1/categorization/groups/grp_unspsc/tags\nAuthorization: Bearer flw_live_***\n```\n\n**Example response (200):**\n```json\n[\n  {\"id\": \"tag_servprof\", \"tagGroupId\": \"grp_unspsc\", \"code\": \"80101504\", \"label\": \"Professional services\"},\n  {\"id\": \"tag_software\", \"tagGroupId\": \"grp_unspsc\", \"code\": \"43232300\", \"label\": \"Software\"}\n]\n```\n\n**Example response (200, empty group):**\n```json\n[]\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`     | Malformed `group_id`.                                           |\n| 401    | `unauthorized`        | Missing / invalid API key.                                      |\n| 403    | `forbidden`           | Key lacks `categorization:read` scope.                          |\n| 404    | `not_found`           | Group does not exist for this org.                              |\n| 422    | `validation_error`    | Path / query failed schema validation.                          |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Internal failure.                                               |\n| 502    | `upstream_error`      | Upstream tag service returned a non-2xx response.               |\n| 503    | `upstream_unavailable`| Upstream tag service unreachable / timed out.                   |",
        "operationId": "list_group_tags_v1_categorization_groups__group_id__tags_get",
        "parameters": [
          {
            "name": "group_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Group Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {},
                "example": [
                  {
                    "id": "tag_servprof",
                    "tagGroupId": "grp_unspsc",
                    "code": "80101504",
                    "label": "Professional services"
                  },
                  {
                    "id": "tag_software",
                    "tagGroupId": "grp_unspsc",
                    "code": "43232300",
                    "label": "Software"
                  }
                ]
              }
            }
          },
          "400": {
            "description": "Malformed request body or path parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream tag service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream tag service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Group, tag, or object not found in the tag service.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/categorization/objects/{object_id}/tags": {
      "get": {
        "tags": [
          "Categorization"
        ],
        "summary": "Get all tags assigned to a document, partner, or supplier",
        "description": "List every tag currently assigned to a single object.\n\n`object_id` can be any Flowie object id — a document (`doc_…`), partner (`prt_…`),\nsupplier, etc. The response is a flat list with the originating group id so the\ncaller can render breadcrumbs (group → tag) without a second round-trip.\n\n---\n\n**Example request:**\n```\nGET /v1/categorization/objects/doc_01HZXABCDEF0123456789/tags\nAuthorization: Bearer flw_live_***\n```\n\n**Example response (200):**\n```json\n[\n  {\n    \"id\": \"oat_01HZXTAGGED012345\",\n    \"objectId\": \"doc_01HZXABCDEF0123456789\",\n    \"objectType\": \"document\",\n    \"tagId\": \"tag_servprof\",\n    \"tagGroupId\": \"grp_unspsc\",\n    \"label\": \"Professional services\",\n    \"assignedAt\": \"2026-06-10T12:34:56Z\"\n  }\n]\n```\n\n**Example response (200, sandbox / no tags):**\n```json\n[]\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`     | Malformed `object_id`.                                          |\n| 401    | `unauthorized`        | Missing / invalid API key.                                      |\n| 403    | `forbidden`           | Key lacks `categorization:read` scope.                          |\n| 404    | `not_found`           | Object not known to the tag service.                            |\n| 422    | `validation_error`    | Path validation failed.                                         |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Internal failure.                                               |\n| 502    | `upstream_error`      | Upstream tag service returned a non-2xx response.               |\n| 503    | `upstream_unavailable`| Upstream tag service unreachable / timed out.                   |",
        "operationId": "get_object_tags_v1_categorization_objects__object_id__tags_get",
        "parameters": [
          {
            "name": "object_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Object Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {},
                "example": [
                  {
                    "id": "oat_01HZXTAGGED012345",
                    "objectId": "doc_01HZXABCDEF0123456789",
                    "objectType": "document",
                    "tagId": "tag_servprof",
                    "tagGroupId": "grp_unspsc",
                    "label": "Professional services",
                    "assignedAt": "2026-06-10T12:34:56Z"
                  }
                ]
              }
            }
          },
          "400": {
            "description": "Malformed request body or path parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream tag service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream tag service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Group, tag, or object not found in the tag service.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Categorization"
        ],
        "summary": "Assign a tag to an object",
        "description": "Assign a single tag to an object (document, partner, supplier, …).\n\nThe request body must be a JSON object containing:\n\n- `tagId` (required) — id of the tag to attach (must already exist in the org).\n- `objectType` (required) — one of `document`, `partner`, `supplier`, `company`.\n\nReturns the newly created `ObjectAssignedTag` record (`oat_…`).\n\n---\n\n**Example request:**\n```\nPOST /v1/categorization/objects/doc_01HZXABCDEF0123456789/tags\nAuthorization: Bearer flw_live_***\nContent-Type: application/json\n\n{\n  \"tagId\": \"tag_servprof\",\n  \"objectType\": \"document\"\n}\n```\n\n**Example response (201):**\n```json\n{\n  \"id\": \"oat_01HZXNEWASSIGN0001\",\n  \"objectId\": \"doc_01HZXABCDEF0123456789\",\n  \"objectType\": \"document\",\n  \"tagId\": \"tag_servprof\",\n  \"assignedAt\": \"2026-06-17T09:21:00Z\"\n}\n```\n\n**Example response (422):**\n```json\n{\n  \"type\": \"about:blank\",\n  \"code\": \"validation_error\",\n  \"message\": \"body must be a JSON object\",\n  \"details\": [{\"field\": \"body\", \"rule\": \"type\", \"message\": \"Input should be a valid dictionary\"}],\n  \"requestId\": \"req_01HZX...\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`     | Missing `tagId` / `objectType`, or unknown values.              |\n| 401    | `unauthorized`        | Missing / invalid API key.                                      |\n| 403    | `forbidden`           | Key lacks `categorization:write` scope.                         |\n| 404    | `not_found`           | Tag or object does not exist.                                   |\n| 409    | `conflict`            | The tag is already assigned to this object.                     |\n| 422    | `validation_error`    | Body failed schema validation (e.g. body not a JSON object).    |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Internal failure.                                               |\n| 502    | `upstream_error`      | Upstream tag service returned a non-2xx response.               |\n| 503    | `upstream_unavailable`| Upstream tag service unreachable / timed out.                   |",
        "operationId": "assign_tag_v1_categorization_objects__object_id__tags_post",
        "parameters": [
          {
            "name": "object_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Object Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "examples": [
                  {
                    "tagId": "tag_servprof",
                    "objectType": "document"
                  },
                  {
                    "tagId": "tag_revenue",
                    "objectType": "supplier"
                  }
                ],
                "title": "Body"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {},
                "example": {
                  "id": "oat_01HZXNEWASSIGN0001",
                  "objectId": "doc_01HZXABCDEF0123456789",
                  "objectType": "document",
                  "tagId": "tag_servprof",
                  "assignedAt": "2026-06-17T09:21:00Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request body or path parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream tag service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream tag service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Group, tag, or object not found in the tag service.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "The same tag is already assigned to this object.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/categorization/objects/{object_id}/tags/{tag_id}": {
      "delete": {
        "tags": [
          "Categorization"
        ],
        "summary": "Remove a tag from an object",
        "description": "Remove a single tag from an object. Idempotent for sandbox keys (no-op).\n\nReturns `204 No Content` on success — no response body.\n\n---\n\n**Example request:**\n```\nDELETE /v1/categorization/objects/doc_01HZXABCDEF0123456789/tags/tag_servprof\nAuthorization: Bearer flw_live_***\n```\n\n**Example response (204):** *(empty body)*\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 401    | `unauthorized`        | Missing / invalid API key.                                      |\n| 403    | `forbidden`           | Key lacks `categorization:write` scope.                         |\n| 404    | `not_found`           | No such assignment.                                             |\n| 422    | `validation_error`    | Path validation failed.                                         |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Internal failure.                                               |\n| 502    | `upstream_error`      | Upstream tag service returned a non-2xx response.               |\n| 503    | `upstream_unavailable`| Upstream tag service unreachable / timed out.                   |",
        "operationId": "remove_tag_v1_categorization_objects__object_id__tags__tag_id__delete",
        "parameters": [
          {
            "name": "object_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Object Id"
            }
          },
          {
            "name": "tag_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Tag Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Tag assignment removed. No content."
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Assignment not found (object or tag never linked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Path failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream tag service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream tag service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/categorization/objects/tags/auto": {
      "post": {
        "tags": [
          "Categorization"
        ],
        "summary": "Get AI-recommended tags for an object",
        "description": "Ask the categorization engine for likely tag assignments.\n\nThe body must be a JSON object naming the target:\n\n- `objectId` (required) — Flowie id of the document / partner / supplier to score.\n- `objectType` (optional, defaults to `document`).\n\nReturns an ordered list of `suggestions`, each with a `tagId`, a `label`, a\n`confidence` in `[0.0, 1.0]`, and a free-text `reasoning` field describing why the\nengine selected that tag. The caller decides whether to auto-apply or surface them\nfor human confirmation.\n\n---\n\n**Example request:**\n```\nPOST /v1/categorization/objects/tags/auto\nAuthorization: Bearer flw_live_***\nContent-Type: application/json\n\n{\"objectId\": \"doc_01HZXABCDEF0123456789\", \"objectType\": \"document\"}\n```\n\n**Example response (200):**\n```json\n{\n  \"objectId\": \"doc_01HZXABCDEF0123456789\",\n  \"objectType\": \"document\",\n  \"suggestions\": [\n    {\"tagId\": \"tag_servprof\", \"label\": \"Professional services\", \"confidence\": 0.92, \"reasoning\": \"Line items mention 'consulting'.\"},\n    {\"tagId\": \"tag_revenue\",  \"label\": \"Revenue\",               \"confidence\": 0.78, \"reasoning\": \"Outgoing invoice.\"}\n  ]\n}\n```\n\n**Example response (400, body not a JSON object):**\n```json\n{\n  \"type\": \"about:blank\",\n  \"code\": \"invalid_request\",\n  \"message\": \"request body must be a JSON object\",\n  \"details\": [],\n  \"requestId\": \"req_01HZX...\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`     | Body not a JSON object, or unknown `objectId`.                  |\n| 401    | `unauthorized`        | Missing / invalid API key.                                      |\n| 403    | `forbidden`           | Key lacks `categorization:read` scope.                          |\n| 422    | `validation_error`    | Body failed schema validation.                                  |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Internal failure.                                               |\n| 502    | `upstream_error`      | Upstream tag service returned a non-2xx response.               |\n| 503    | `upstream_unavailable`| Upstream tag service unreachable / timed out.                   |",
        "operationId": "auto_recommend_v1_categorization_objects_tags_auto_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "examples": [
                  {
                    "objectId": "doc_01HZXABCDEF0123456789",
                    "objectType": "document"
                  },
                  {
                    "objectId": "prt_01HZXPARTNER0000001",
                    "objectType": "partner"
                  }
                ],
                "title": "Body"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {},
                "example": {
                  "objectId": "doc_01HZXABCDEF0123456789",
                  "objectType": "document",
                  "suggestions": [
                    {
                      "tagId": "tag_servprof",
                      "label": "Professional services",
                      "confidence": 0.92,
                      "reasoning": "Line items mention 'consulting' and 'advisory'."
                    },
                    {
                      "tagId": "tag_revenue",
                      "label": "Revenue",
                      "confidence": 0.78,
                      "reasoning": "Outgoing invoice booked against revenue account."
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Malformed request body or path parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but lacks permission for this resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream tag service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream tag service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/payments/documents/{documentId}": {
      "get": {
        "tags": [
          "Payments"
        ],
        "summary": "Get payment information for a document (invoice / PO)",
        "description": "Return the payment ledger for a single document (typically an invoice or PO).\n\nThe response includes every individual `Payment` record linked to the document, the\n`totalPaid` so far, the remaining `balanceDue` (when the document amount is known),\nand the document's `currency`. Sandbox API keys receive an empty ledger.\n\n---\n\n**Example request:**\n```\nGET /v1/payments/documents/doc_01HZXABCDEF0123456789\nAuthorization: Bearer flw_live_***\n```\n\n**Example response (200):**\n```json\n{\n  \"objectId\": \"doc_01HZXABCDEF0123456789\",\n  \"objectType\": \"document\",\n  \"organizationId\": \"comp_abc123\",\n  \"payments\": [\n    {\n      \"id\": \"pay_01HZXPAID0000001\",\n      \"amount\": 1200.00,\n      \"currency\": \"EUR\",\n      \"paidAt\": \"2026-06-10T13:42:11Z\",\n      \"method\": \"SEPA\",\n      \"reference\": \"INV-2026-0042\",\n      \"status\": \"recorded\"\n    }\n  ],\n  \"balanceDue\": 0.00,\n  \"totalPaid\": 1200.00,\n  \"currency\": \"EUR\"\n}\n```\n\n**Example response (404):**\n```json\n{\n  \"type\": \"about:blank\",\n  \"code\": \"not_found\",\n  \"message\": \"Document doc_01HZXABCDEF0123456789 not found\",\n  \"details\": [],\n  \"requestId\": \"req_01HZX...\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`     | Malformed `documentId`.                                         |\n| 401    | `unauthorized`        | Missing / invalid API key.                                      |\n| 403    | `forbidden`           | Key lacks `payments` scope.                                     |\n| 404    | `not_found`           | Document does not exist for this org.                           |\n| 422    | `validation_error`    | Path validation failed.                                         |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Internal failure.                                               |\n| 502    | `upstream_error`      | Upstream payment service returned a non-2xx response.           |\n| 503    | `upstream_unavailable`| Upstream payment service unreachable / timed out.               |",
        "operationId": "get_document_payments_v1_payments_documents__documentId__get",
        "parameters": [
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Documentid"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {},
                "example": {
                  "objectId": "doc_01HZXABCDEF0123456789",
                  "objectType": "document",
                  "organizationId": "comp_abc123",
                  "payments": [
                    {
                      "id": "pay_01HZXPAID0000001",
                      "amount": 1200.0,
                      "currency": "EUR",
                      "paidAt": "2026-06-10T13:42:11Z",
                      "method": "SEPA",
                      "reference": "INV-2026-0042",
                      "status": "recorded"
                    }
                  ],
                  "balanceDue": 0.0,
                  "totalPaid": 1200.0,
                  "currency": "EUR"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request body or path parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the `payments` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream payment service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream payment service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Document / payment object not found for this organisation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/payments/documents/{documentId}/pay": {
      "post": {
        "tags": [
          "Payments"
        ],
        "summary": "Record a payment against a document",
        "description": "Record a payment made against a document (invoice or PO).\n\nBody fields:\n\n- `amount` (required) — numeric amount paid (use a positive number).\n- `date` (optional) — `YYYY-MM-DD` (or an ISO 8601 timestamp). `paidAt` is\n  accepted as an alias.\n- `reference` (optional) — free-form external reference (e.g. bank txn id).\n- `currency` (optional, default `EUR`) — ISO 4217 code.\n- `method` (optional) — `SEPA`, `card`, `cheque`, `cash`, `wire`, `other`.\n- `note` (optional) — free-text comment stored on the payment.\n\nReturns the created `Payment` record. The document's `totalPaid` and `balanceDue`\nare recomputed on the next `GET /v1/payments/documents/{documentId}`.\n\nThe document lifecycle is advanced to `partially_paid`, or `paid` once the\nrecorded payments cover `totalAmountDue`. This is best-effort: the payment is\nrecorded regardless, and `lifecycleStatus` in the response is `null` when the\ntransition was not permitted from the document's current status (only\n`approved`, `partially_paid` and `disputed` can move to a paid state — see\n`GET /v1/documents/{documentId}/lifecycle` → `allowedTransitions`).\n\n---\n\n**Example request:**\n```\nPOST /v1/payments/documents/doc_01HZXABCDEF0123456789/pay\nAuthorization: Bearer flw_live_***\nContent-Type: application/json\n\n{\n  \"amount\": 1200.00,\n  \"currency\": \"EUR\",\n  \"method\": \"SEPA\",\n  \"paidAt\": \"2026-06-17T09:30:00Z\",\n  \"reference\": \"INV-2026-0042\"\n}\n```\n\n**Example response (201):**\n```json\n{\n  \"id\": \"pay_01HZXNEW000000001\",\n  \"objectId\": \"doc_01HZXABCDEF0123456789\",\n  \"objectType\": \"document\",\n  \"organizationId\": \"comp_abc123\",\n  \"amount\": 1200.00,\n  \"currency\": \"EUR\",\n  \"paidAt\": \"2026-06-17T09:30:00Z\",\n  \"method\": \"SEPA\",\n  \"reference\": \"INV-2026-0042\",\n  \"status\": \"recorded\",\n  \"createdAt\": \"2026-06-17T09:30:00Z\"\n}\n```\n\n**Example response (422):**\n```json\n{\n  \"type\": \"about:blank\",\n  \"code\": \"validation_error\",\n  \"message\": \"amount must be a positive number\",\n  \"details\": [{\"field\": \"amount\", \"rule\": \"gt\", \"message\": \"ensure this value is greater than 0\"}],\n  \"requestId\": \"req_01HZX...\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`     | Missing `amount`, unknown `method`, malformed `paidAt`.         |\n| 401    | `unauthorized`        | Missing / invalid API key.                                      |\n| 403    | `forbidden`           | Key lacks `payments` scope.                                     |\n| 404    | `not_found`           | Document does not exist for this org.                           |\n| 409    | `conflict`            | Duplicate payment (idempotency clash / reference re-used).      |\n| 422    | `validation_error`    | Body schema validation failed.                                  |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Internal failure.                                               |\n| 502    | `upstream_error`      | Upstream payment service returned a non-2xx response.           |\n| 503    | `upstream_unavailable`| Upstream payment service unreachable / timed out.               |",
        "operationId": "record_document_payment_v1_payments_documents__documentId__pay_post",
        "parameters": [
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Documentid"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "examples": [
                  {
                    "amount": 1200.0,
                    "date": "2026-06-17",
                    "reference": "INV-2026-0042"
                  },
                  {
                    "amount": 500.0,
                    "date": "2026-06-17",
                    "currency": "USD",
                    "method": "card",
                    "reference": "PO-2026-0099"
                  }
                ],
                "title": "Body"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {},
                "example": {
                  "id": "pay_01HZXNEW000000001",
                  "objectId": "doc_01HZXABCDEF0123456789",
                  "objectType": "document",
                  "organizationId": "comp_abc123",
                  "amount": 1200.0,
                  "currency": "EUR",
                  "paidAt": "2026-06-17T09:30:00Z",
                  "method": "SEPA",
                  "reference": "INV-2026-0042",
                  "status": "recorded",
                  "createdAt": "2026-06-17T09:30:00Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request body or path parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the `payments` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream payment service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream payment service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Document / payment object not found for this organisation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "A payment with the same idempotency key / reference already exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/payments/export/iso20022": {
      "post": {
        "tags": [
          "Payments"
        ],
        "summary": "Generate an ISO 20022 (SEPA pain.001) payment file",
        "description": "Generate an ISO 20022 (`pain.001.001.09`) SEPA Credit Transfer Initiation file.\n\nBundles one or more documents into a single payment file the caller can hand to its\nbank. The returned `content` is base64-encoded XML — decode it before saving / upload.\n\nBody fields:\n\n- `documentIds` (required) — list of document ids to include. Each must have a\n  registered creditor bank account and a non-zero outstanding balance.\n- `currency` (optional, default `EUR`) — ISO 4217 currency the bundle is settled in.\n- `executionDate` (optional) — ISO 8601 date on which the bank should execute the\n  payments. Defaults to next business day.\n\nSandbox keys receive a minimal placeholder pain.001 with `transactionCount: 0`.\n\n---\n\n**Example request:**\n```\nPOST /v1/payments/export/iso20022\nAuthorization: Bearer flw_live_***\nContent-Type: application/json\n\n{\n  \"documentIds\": [\"doc_01HZXABCDEF0123456789\", \"doc_01HZXABCDEF0123456790\"],\n  \"currency\": \"EUR\",\n  \"executionDate\": \"2026-06-18\"\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"messageId\": \"MSG-2026-06-17-0001\",\n  \"organizationId\": \"comp_abc123\",\n  \"format\": \"pain.001.001.09\",\n  \"filename\": \"MSG-2026-06-17-0001.xml\",\n  \"content\": \"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4K…\",\n  \"contentType\": \"application/xml\",\n  \"transactionCount\": 2,\n  \"totalAmount\": 2400.00,\n  \"currency\": \"EUR\",\n  \"generatedAt\": \"2026-06-17T09:35:14Z\"\n}\n```\n\n**Example response (400):**\n```json\n{\n  \"type\": \"about:blank\",\n  \"code\": \"invalid_request\",\n  \"message\": \"documentIds must contain at least one document\",\n  \"details\": [{\"field\": \"documentIds\", \"rule\": \"min_items\", \"message\": \"ensure this list has at least 1 items\"}],\n  \"requestId\": \"req_01HZX...\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                  | When                                                            |\n|--------|-----------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`     | Empty `documentIds`, malformed `executionDate`, unknown currency.|\n| 401    | `unauthorized`        | Missing / invalid API key.                                      |\n| 403    | `forbidden`           | Key lacks `payments` scope.                                     |\n| 422    | `validation_error`    | Body schema validation failed.                                  |\n| 429    | `rate_limited`        | Too many requests — retry after `Retry-After` seconds.          |\n| 500    | `internal_error`      | Internal failure.                                               |\n| 502    | `upstream_error`      | Upstream payment service returned a non-2xx response.           |\n| 503    | `upstream_unavailable`| Upstream payment service unreachable / timed out.               |",
        "operationId": "export_iso20022_v1_payments_export_iso20022_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "examples": [
                  {
                    "documentIds": [
                      "doc_01HZXABCDEF0123456789",
                      "doc_01HZXABCDEF0123456790",
                      "doc_01HZXABCDEF0123456791"
                    ],
                    "currency": "EUR",
                    "executionDate": "2026-06-18"
                  }
                ],
                "title": "Body"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {},
                "example": {
                  "messageId": "MSG-2026-06-17-0001",
                  "organizationId": "comp_abc123",
                  "format": "pain.001.001.09",
                  "filename": "MSG-2026-06-17-0001.xml",
                  "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4K…(base64)…",
                  "contentType": "application/xml",
                  "transactionCount": 3,
                  "totalAmount": 4525.5,
                  "currency": "EUR",
                  "generatedAt": "2026-06-17T09:35:14Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request body or path parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the `payments` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body / query failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream payment service returned an error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream payment service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/me": {
      "get": {
        "tags": [
          "Identity"
        ],
        "summary": "Get the caller identity + accessible organizations",
        "description": "Return the caller's identity plus the organizations they can act as.\n\nThis is the first call most integrations make — the docs auth widget reads it\nto render the organization switcher, and clients use it to verify their API key\nis valid and to discover the org id to send in `X-Flowie-Organization-Id` on\nsubsequent requests.\n\nFor **JWT** auth, `organizationIds` is every org in the user's `_permissions`\nclaim. For **API-key** auth, it is the single org the key is bound to (no\nswitching). Org-v2 enrichment is best-effort and bounded — on partial outage\nthe array may contain id-only entries (`name` / `country` / `vatNumber` null).\n\n**Example request:**\n```http\nGET /v1/me\nAuthorization: Bearer flw_live_…\n```\n\n**Example response (200):**\n```json\n{\n  \"authMethod\": \"api_key\",\n  \"userId\": null,\n  \"email\": null,\n  \"keyType\": \"personal\",\n  \"organizationId\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n  \"organizationIds\": [\"019a6e5b-3960-7000-ab88-153aed5a6240\"],\n  \"organizations\": [\n    {\n      \"id\": \"019a6e5b-3960-7000-ab88-153aed5a6240\",\n      \"name\": \"HOZELOCK EXEL\",\n      \"country\": \"FR\",\n      \"vatNumber\": \"FR02779658772\"\n    }\n  ],\n  \"scopes\": [\"*\"],\n  \"isTestMode\": false\n}\n```\n\n**Example error (401 — bad key):**\n```json\n{\n  \"type\": \"unauthorized\",\n  \"code\": \"invalid_api_key\",\n  \"message\": \"API key is missing or invalid.\",\n  \"details\": [],\n  \"requestId\": \"req_01HX...\"\n}\n```\n\n**Errors** (body follows `ErrorResponse`):\n\n| Status | Code                   | When                                                          |\n|--------|------------------------|---------------------------------------------------------------|\n| 401    | `unauthorized`         | Missing / invalid API key or bearer token.                    |\n| 403    | `forbidden`            | Key type not permitted on this endpoint.                      |\n| 429    | `rate_limited`         | Too many requests.                                            |\n| 502    | `upstream_error`       | Org-v2 returned a non-2xx during enrichment (rare — bounded). |\n| 503    | `upstream_unavailable` | Org-v2 unreachable / enrichment budget exhausted.             |",
        "operationId": "get_me_v1_me_get",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Caller identity + the orgs they can switch to (enrichment is best-effort).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Get Me V1 Me Get"
                },
                "example": {
                  "authMethod": "api_key",
                  "keyType": "personal",
                  "organizationId": "019a6e5b-3960-7000-ab88-153aed5a6240",
                  "organizationIds": [
                    "019a6e5b-3960-7000-ab88-153aed5a6240",
                    "019a6e5b-3960-7000-ab88-153aed5a6241"
                  ],
                  "organizations": [
                    {
                      "id": "019a6e5b-3960-7000-ab88-153aed5a6240",
                      "name": "HOZELOCK EXEL",
                      "country": "FR",
                      "vatNumber": "FR02779658772"
                    },
                    {
                      "id": "019a6e5b-3960-7000-ab88-153aed5a6241",
                      "name": "FLOWIE",
                      "country": "FR",
                      "vatNumber": "FR26921376265"
                    }
                  ],
                  "scopes": [
                    "*"
                  ],
                  "isTestMode": false
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Token valid but its key type is not allowed on this endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream org-v2 returned an error during enrichment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream org-v2 unavailable / timed out (enrichment is best-effort; the endpoint may still return id-only entries on partial outage).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/flow-service/v1/healthcheck": {
      "get": {
        "tags": [
          "AFNOR Flow Service"
        ],
        "summary": "Health check",
        "description": "Liveness probe required by AFNOR XP Z12-013 v1.3.0 § 5 (PDP→PA reachability check).\n\nReturns a static `{\"status\": \"ok\"}` payload so partner PDPs (DCSnet, Symtrax, …) can\nverify the Flow-Service facade is reachable before exercising the actual `/v1/flows/*`\nor `/v1/webhooks/*` routes. No authentication required, no upstream calls made.\n\n**Example response (200):**\n```json\n{\"status\": \"ok\"}\n```\n\n**Errors**\n\n| Status | Code                   | When                          |\n|--------|------------------------|-------------------------------|\n| 503    | `SERVICE_UNAVAILABLE`  | Process not yet ready / dying. |",
        "operationId": "healthcheck_afnor_flow_service_v1_healthcheck_get",
        "responses": {
          "200": {
            "description": "Service is live.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Healthcheck Afnor Flow Service V1 Healthcheck Get"
                },
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/flow-service/v1/flows": {
      "post": {
        "tags": [
          "AFNOR Flow Service"
        ],
        "summary": "Submit a flow (createFlow)",
        "description": "Submit a document flow for asynchronous PA-side processing — AFNOR XP Z12-013 v1.3.0\n§ 6.2 `createFlow`. The PA performs syntactic + semantic checks, attaches the\n`processingRule`, persists the artifact, and (when the recipient is reachable) hands\nthe flow over to the destination PDP. The 202 response carries the PA-assigned\n`flowId` and a timestamp — final delivery status arrives later via the\n`document.sent.*` webhook.\n\n**Multipart parts**\n\n- `flowInfo` (required) — JSON-serialised `FlowInfo` object (`name`, `flowSyntax`,\n  `trackingId`, `processingRule`, `flowProfile`, `sha256`).\n- `file` (optional) — binary document body. UTF-8 XML for `UBL` / `CII` / `CDAR` /\n  `FRR`, PDF/A-3 for `Factur-X`. Omit only for control flows.\n\n**Example `flowInfo` part:**\n```json\n{\n  \"name\": \"FA-2026-000123\",\n  \"flowSyntax\": \"UBL\",\n  \"trackingId\": \"TRK-2026-000123\",\n  \"processingRule\": \"B2B\",\n  \"flowProfile\": \"CIUS\",\n  \"sha256\": \"9b74c9897bac770ffc029102a200c5de7afbab8e1f0f1e6d39e6a8b3c0d1e2f3\"\n}\n```\n\n**Example response (202 Accepted):**\n```json\n{\n  \"flowId\": \"e89d4676-eb0c-4aa0-a8aa-3c519a2ed145\",\n  \"submittedAt\": \"2026-06-17T09:15:32.512Z\",\n  \"name\": \"FA-2026-000123\",\n  \"flowSyntax\": \"UBL\",\n  \"trackingId\": \"TRK-2026-000123\",\n  \"processingRule\": \"B2B\",\n  \"flowProfile\": \"CIUS\",\n  \"sha256\": \"9b74c9897bac770ffc029102a200c5de7afbab8e1f0f1e6d39e6a8b3c0d1e2f3\"\n}\n```\n\n**Example error (400 — bad `flowInfo` JSON):**\n```json\n{\n  \"errorCode\": \"BAD_REQUEST\",\n  \"errorMessage\": \"Invalid flowInfo JSON: Expecting property name enclosed in double quotes\",\n  \"type\": \"about:blank\"\n}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                          |\n|--------|-------------------------|---------------------------------------------------------------|\n| 400    | `BAD_REQUEST`       | Bad `flowInfo` JSON, unknown `flowSyntax`, bad SHA-256 hex.   |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                                    |\n| 403    | `FORBIDDEN_ACCESS`             | Key lacks Flow-Service scope or wrong `Organization-Id`.      |\n| 413    | `FILE_SIZE_EXCEEDED`     | `file` exceeds 25 MiB.                                        |\n| 415    | `UNSUPPORTED_MEDIA_TYPE`     | `file` content does not match declared `flowSyntax`.          |\n| 422    | `UNPROCESSABLE_ENTITY`      | `FlowInfo` schema validation failed (e.g. `name` >255 chars). |\n| 429    | `TOO_MANY_REQUESTS`          | PDP submission quota exhausted.                               |\n| 502    | `UPSTREAM_ERROR`        | `document_service.send_document` rejected the payload.        |\n| 503    | `SERVICE_UNAVAILABLE`  | tx-doc store or signing service unreachable.                  |",
        "operationId": "create_flow_afnor_flow_service_v1_flows_post",
        "parameters": [
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          },
          {
            "name": "Request-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Request-Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/Body_create_flow_afnor_flow_service_v1_flows_post"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Flow accepted for asynchronous processing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFlowInfo"
                },
                "example": {
                  "flowId": "e89d4676-eb0c-4aa0-a8aa-3c519a2ed145",
                  "submittedAt": "2026-06-17T09:15:32.512Z",
                  "name": "FA-2026-000123",
                  "flowSyntax": "UBL",
                  "trackingId": "TRK-2026-000123",
                  "processingRule": "B2B",
                  "flowProfile": "CIUS",
                  "sha256": "9b74c9897bac770ffc029102a200c5de7afbab8e1f0f1e6d39e6a8b3c0d1e2f3"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request body (e.g. invalid `flowInfo` JSON, unknown `docType`, bad SHA-256).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the AFNOR Flow-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed AFNOR schema validation (FlowInfo, SearchFlowFilters, WebhookParams…).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (document_service / webhook_service / tx-doc) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "413": {
            "description": "Uploaded `file` exceeds the AFNOR 25 MiB ceiling.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported `flowSyntax` for the supplied content (e.g. PDF when CII is declared).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/flow-service/v1/flows/search": {
      "post": {
        "tags": [
          "AFNOR Flow Service"
        ],
        "summary": "Search flows (searchFlows)",
        "description": "Page through flows matching the AFNOR filter set — XP Z12-013 v1.3.0 § 6.3\n`searchFlows`. Filters are AND-combined across keys; arrays within a single key are\nOR-combined. Results are returned in `updatedAt` ascending order.\n\n**Pagination.** Pass `limit` (max 100) to size the page. When more rows remain the\nresponse carries an opaque `nextCursor`; re-send the identical request with\n`cursor` set to that value to fetch the next page. The cursor is stateless\n(base64 of an offset) — the last page omits `nextCursor` entirely. Keep `where`\nstable across a pagination run.\n\nBehavior intentionally hard-filters on `flowType` / `flowDirection` after mapping\nto the internal `document_service.list_documents` shape — the upstream filter is\nbest-effort and `flowType` ↔ document-type is many-to-one. Without the post-filter\na `CustomerInvoice/Out` query could surface `SupplierInvoice/In` rows (the bug\nDCSnet reported on 2026-06-08), and a lifecycle (`…LC`) query would leak plain\ninvoices instead of returning an empty page.\n\n**Example request:**\n```json\n{\n  \"limit\": 25,\n  \"where\": {\n    \"updatedAfter\": \"2026-06-01T00:00:00Z\",\n    \"processingRule\": [\"B2B\", \"NotApplicable\"],\n    \"flowType\": [\"CustomerInvoice\"],\n    \"flowDirection\": [\"Out\"],\n    \"ackStatus\": \"Ok\"\n  }\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"limit\": 25,\n  \"filters\": {\n    \"flowType\": [\"CustomerInvoice\"],\n    \"flowDirection\": [\"Out\"],\n    \"processingRule\": [\"B2B\", \"NotApplicable\"],\n    \"ackStatus\": \"Ok\"\n  },\n  \"results\": [\n    {\n      \"flowId\": \"e89d4676-eb0c-4aa0-a8aa-3c519a2ed145\",\n      \"submittedAt\": \"2026-06-17T09:15:32.512Z\",\n      \"name\": \"FA-2026-000123\",\n      \"flowSyntax\": \"UBL\",\n      \"trackingId\": \"TRK-2026-000123\",\n      \"processingRule\": \"B2B\",\n      \"flowProfile\": \"CIUS\",\n      \"updatedAt\": \"2026-06-17T09:17:01.004Z\",\n      \"flowType\": \"CustomerInvoice\",\n      \"processingRuleSource\": \"Computed\",\n      \"flowDirection\": \"Out\",\n      \"acknowledgement\": {\"status\": \"Ok\", \"details\": []}\n    }\n  ]\n}\n```\n\n**Example response (200 — lifecycle query returns empty for non-LC corpora):**\n```json\n{\"limit\": 25, \"filters\": {\"flowType\": [\"CustomerInvoiceLC\"]}, \"results\": []}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                            |\n|--------|-------------------------|-----------------------------------------------------------------|\n| 400    | `BAD_REQUEST`       | Filter combination not honored by the upstream document store.  |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                                      |\n| 403    | `FORBIDDEN_ACCESS`             | `Organization-Id` not visible to the calling key.               |\n| 422    | `UNPROCESSABLE_ENTITY`      | `SearchFlowParams` failed schema validation (bad enum, dates).  |\n| 429    | `TOO_MANY_REQUESTS`          | Search quota exhausted.                                         |\n| 502    | `UPSTREAM_ERROR`        | `document_service.list_documents` raised.                       |\n| 503    | `SERVICE_UNAVAILABLE`  | Document store unreachable / timed out.                         |",
        "operationId": "search_flows_afnor_flow_service_v1_flows_search_post",
        "parameters": [
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchFlowParams"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Page of matching flows (ordered by `updatedAt` ascending).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchFlowResponse"
                },
                "example": {
                  "limit": 25,
                  "nextCursor": "eyJvZmZzZXQiOiAyNX0=",
                  "filters": {
                    "flowType": [
                      "CustomerInvoice"
                    ],
                    "flowDirection": [
                      "Out"
                    ],
                    "processingRule": [
                      "B2B"
                    ]
                  },
                  "results": [
                    {
                      "flowId": "e89d4676-eb0c-4aa0-a8aa-3c519a2ed145",
                      "submittedAt": "2026-06-17T09:15:32.512Z",
                      "name": "FA-2026-000123",
                      "flowSyntax": "UBL",
                      "trackingId": "TRK-2026-000123",
                      "processingRule": "B2B",
                      "flowProfile": "CIUS",
                      "updatedAt": "2026-06-17T09:17:01.004Z",
                      "flowType": "CustomerInvoice",
                      "processingRuleSource": "Computed",
                      "flowDirection": "Out",
                      "acknowledgement": {
                        "status": "Ok"
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Malformed request body (e.g. invalid `flowInfo` JSON, unknown `docType`, bad SHA-256).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the AFNOR Flow-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed AFNOR schema validation (FlowInfo, SearchFlowFilters, WebhookParams…).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (document_service / webhook_service / tx-doc) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/flow-service/v1/flows/{flow_id}": {
      "get": {
        "tags": [
          "AFNOR Flow Service"
        ],
        "summary": "Download a flow (getFlow)",
        "description": "Retrieve a single flow by its AFNOR `flowId` — XP Z12-013 v1.3.0 § 6.4 `getFlow`.\nThe `docType` query parameter selects the rendering, matching the AFNOR spec:\n\n- `Metadata` — JSON `Flow` object (default), useful for polling ack status.\n- `Original` — raw bytes of the originally received XML (UBL preferred, CII fallback).\n- `Converted` — the other syntax, lazily generated if the flow was JSON-only on intake.\n- `ReadableView` — the human-readable PDF derived from the XML.\n\nThe `Organization-Id` header is forwarded to the document service so partner tokens\n(e.g. DCSnet's PDP key accessing a Reynolds-owned flow) resolve against the AFNOR\norganisation, not the API key's home org.\n\n**Example response (`docType=Metadata`, 200):**\n```json\n{\n  \"flowId\": \"e89d4676-eb0c-4aa0-a8aa-3c519a2ed145\",\n  \"submittedAt\": \"2026-06-17T09:15:32.512Z\",\n  \"name\": \"FA-2026-000123\",\n  \"flowSyntax\": \"UBL\",\n  \"trackingId\": \"TRK-2026-000123\",\n  \"processingRule\": \"B2B\",\n  \"flowProfile\": \"CIUS\",\n  \"updatedAt\": \"2026-06-17T09:17:01.004Z\",\n  \"flowType\": \"CustomerInvoice\",\n  \"processingRuleSource\": \"Computed\",\n  \"flowDirection\": \"Out\",\n  \"acknowledgement\": {\"status\": \"Ok\", \"details\": []}\n}\n```\n\n**Example response (`docType=Original`, 200):**\n```xml\n<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\">\n  <cbc:ID>FA-2026-000123</cbc:ID>\n  <cbc:IssueDate>2026-06-17</cbc:IssueDate>\n</Invoice>\n```\n\n**Example error (404):**\n```json\n{\"errorCode\": \"404\", \"errorMessage\": \"Flow e89d4676-... not found\"}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                              |\n|--------|-------------------------|-------------------------------------------------------------------|\n| 400    | `BAD_REQUEST`       | `docType` not one of `Metadata/Original/ReadableView/Converted`.  |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                                        |\n| 403    | `FORBIDDEN_ACCESS`             | `Organization-Id` not authorised for this flow.                   |\n| 404    | `NOT_FOUND`             | Flow ID unknown or not visible to caller.                         |\n| 422    | `UNPROCESSABLE_ENTITY`      | `flow_id` is not a UUID-shaped string.                            |\n| 429    | `TOO_MANY_REQUESTS`          | Download quota exhausted.                                         |\n| 502    | `UPSTREAM_ERROR`        | `document_service` failed to fetch XML / generate PDF.            |\n| 503    | `SERVICE_UNAVAILABLE`  | Document store unreachable.                                       |",
        "operationId": "get_flow_afnor_flow_service_v1_flows__flow_id__get",
        "parameters": [
          {
            "name": "flow_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Flow Id"
            }
          },
          {
            "name": "docType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Metadata | Original | ReadableView | Converted",
              "default": "Metadata",
              "title": "Doctype"
            },
            "description": "Metadata | Original | ReadableView | Converted"
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Flow content. The response body is JSON for `docType=Metadata`, raw XML for `Original` / `Converted` (UBL or CII), and PDF bytes for `ReadableView`.",
            "content": {
              "application/json": {
                "schema": {},
                "example": {
                  "flowId": "e89d4676-eb0c-4aa0-a8aa-3c519a2ed145",
                  "submittedAt": "2026-06-17T09:15:32.512Z",
                  "name": "FA-2026-000123",
                  "flowSyntax": "UBL",
                  "trackingId": "TRK-2026-000123",
                  "processingRule": "B2B",
                  "flowProfile": "CIUS",
                  "updatedAt": "2026-06-17T09:17:01.004Z",
                  "flowType": "CustomerInvoice",
                  "processingRuleSource": "Computed",
                  "flowDirection": "Out",
                  "acknowledgement": {
                    "status": "Ok",
                    "details": []
                  }
                }
              },
              "application/xml": {
                "example": "<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"><cbc:ID>FA-2026-000123</cbc:ID></Invoice>"
              },
              "application/pdf": {
                "example": "<binary PDF bytes>"
              }
            }
          },
          "400": {
            "description": "Malformed request body (e.g. invalid `flowInfo` JSON, unknown `docType`, bad SHA-256).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the AFNOR Flow-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed AFNOR schema validation (FlowInfo, SearchFlowFilters, WebhookParams…).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (document_service / webhook_service / tx-doc) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "404": {
            "description": "Requested flow / webhook does not exist or is not visible to the calling organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/flow-service/v1/webhooks": {
      "get": {
        "tags": [
          "AFNOR Flow Service"
        ],
        "summary": "List webhooks (listWebhooks)",
        "description": "List the webhook subscriptions registered against the caller's organisation —\nXP Z12-013 v1.3.0 § 6.5 `listWebhooks`. The result is scoped by the `Organization-Id`\nheader; internal Flowie event types are mapped back to AFNOR `metadata`\n(`flowDirection` / `ackStatus`) on the way out.\n\n**Example response (200):**\n```json\n{\n  \"count\": 1,\n  \"webhooks\": [\n    {\n      \"webhookId\": \"wh_01HZX0F6N1B3KQAM7VV9G8T0YT\",\n      \"callbackUrl\": \"https://partner.example.com/afnor/callback\",\n      \"flowTypes\": [\"CustomerInvoice\"],\n      \"flowDirection\": \"Out\",\n      \"ackStatus\": \"Ok\"\n    }\n  ]\n}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                |\n|--------|-------------------------|-----------------------------------------------------|\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                          |\n| 403    | `FORBIDDEN_ACCESS`             | `Organization-Id` not visible to the calling key.   |\n| 429    | `TOO_MANY_REQUESTS`          | Listing quota exhausted.                            |\n| 502    | `UPSTREAM_ERROR`        | `webhook_service.list_webhooks` raised.             |\n| 503    | `SERVICE_UNAVAILABLE`  | Webhook store unreachable.                          |",
        "operationId": "list_webhooks_afnor_flow_service_v1_webhooks_get",
        "parameters": [
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "All webhook subscriptions visible to the caller (filtered by `Organization-Id`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorWebhookList"
                },
                "example": {
                  "count": 1,
                  "webhooks": [
                    {
                      "webhookId": "wh_01HZX0F6N1B3KQAM7VV9G8T0YT",
                      "callbackUrl": "https://partner.example.com/afnor/callback",
                      "flowTypes": [
                        "CustomerInvoice"
                      ],
                      "flowDirection": "Out",
                      "ackStatus": "Ok"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Malformed request body (e.g. invalid `flowInfo` JSON, unknown `docType`, bad SHA-256).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the AFNOR Flow-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed AFNOR schema validation (FlowInfo, SearchFlowFilters, WebhookParams…).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (document_service / webhook_service / tx-doc) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "AFNOR Flow Service"
        ],
        "summary": "Create webhook (createWebhook)",
        "description": "Subscribe a partner callback URL to AFNOR Flow-Service events — XP Z12-013 v1.3.0\n§ 6.6 `createWebhook`. The supplied `metadata` (`flowType` / `flowDirection` /\n`ackStatus`) is translated to internal event names like `document.sent.ok` or\n`document.received.error`; subsequent flow state transitions matching that filter\nfire a POST to `callback.url` carrying a `Flow` payload.\n\n**Example request (AFNOR swagger shape — source of truth):**\n```json\n{\n  \"callbackUrl\": \"https://partner.example.com/afnor/callback\",\n  \"flowTypes\": [\"CustomerInvoice\"],\n  \"flowDirection\": \"Out\",\n  \"ackStatus\": \"Ok\"\n}\n```\n\nThe legacy nested body `{callback: {url}, metadata: {…}}` is still accepted\nfor backward compatibility, but the response always follows the swagger\n`WebhookIdParam` shape below.\n\n**Example response (201):**\n```json\n{\n  \"webhookId\": \"wh_01HZX0F6N1B3KQAM7VV9G8T0YT\",\n  \"signingKey\": \"b3f1c0a9d4e5...secret-hex...\",\n  \"createdAt\": \"2026-06-17T09:15:32.512Z\"\n}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                          |\n|--------|-------------------------|---------------------------------------------------------------|\n| 400    | `BAD_REQUEST`       | `callback.url` is not https, or `metadata.flowDirection`      |\n|        |                         | / `ackStatus` outside the AFNOR enum.                         |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                                    |\n| 403    | `FORBIDDEN_ACCESS`             | Key lacks `webhook:write` scope.                              |\n| 409    | `CONFLICT`              | Duplicate subscription (same url + metadata) already active.  |\n| 422    | `UNPROCESSABLE_ENTITY`      | `WebhookParams` failed schema validation.                     |\n| 429    | `TOO_MANY_REQUESTS`          | Webhook creation quota exhausted.                             |\n| 502    | `UPSTREAM_ERROR`        | `webhook_service.create_webhook` raised.                      |\n| 503    | `SERVICE_UNAVAILABLE`  | Webhook store unreachable.                                    |",
        "operationId": "create_webhook_afnor_flow_service_v1_webhooks_post",
        "parameters": [
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookParams"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook subscription created — returns the id + signing key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorWebhookCreated"
                },
                "example": {
                  "webhookId": "wh_01HZX0F6N1B3KQAM7VV9G8T0YT",
                  "signingKey": "b3f1c0a9d4e5...secret-hex...",
                  "createdAt": "2026-06-17T09:15:32.512Z"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request body (e.g. invalid `flowInfo` JSON, unknown `docType`, bad SHA-256).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the AFNOR Flow-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed AFNOR schema validation (FlowInfo, SearchFlowFilters, WebhookParams…).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (document_service / webhook_service / tx-doc) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "409": {
            "description": "An identical (url + metadata) subscription already exists for this org.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/flow-service/v1/webhooks/{webhook_uid}": {
      "get": {
        "tags": [
          "AFNOR Flow Service"
        ],
        "summary": "Get webhook detail (getWebhook)",
        "description": "Fetch a single webhook subscription by its `webhookId` — XP Z12-013 v1.3.0 § 6.7\n`getWebhook`. Implemented as a filter over `webhook_service.list_webhooks` for the\nsame `Organization-Id`, so 404 is returned both when the ID does not exist and when\nit does but belongs to another org (no cross-tenant leak).\n\n**Example response (200):**\n```json\n{\n  \"webhookId\": \"wh_01HZX0F6N1B3KQAM7VV9G8T0YT\",\n  \"callbackUrl\": \"https://partner.example.com/afnor/callback\",\n  \"flowTypes\": [\"CustomerInvoice\"],\n  \"flowDirection\": \"Out\",\n  \"ackStatus\": \"Ok\"\n}\n```\n\n**Example error (404):**\n```json\n{\"errorCode\": \"404\", \"errorMessage\": \"Webhook wh_... not found\"}\n```\n\n**Errors**\n\n| Status | Code                    | When                                              |\n|--------|-------------------------|---------------------------------------------------|\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                        |\n| 403    | `FORBIDDEN_ACCESS`             | `Organization-Id` not authorised.                 |\n| 404    | `NOT_FOUND`             | Webhook ID unknown or owned by another org.       |\n| 422    | `UNPROCESSABLE_ENTITY`      | `webhook_uid` failed path validation.             |\n| 429    | `TOO_MANY_REQUESTS`          | Listing quota exhausted.                          |\n| 502    | `UPSTREAM_ERROR`        | Webhook store returned a non-2xx response.        |\n| 503    | `SERVICE_UNAVAILABLE`  | Webhook store unreachable.                        |",
        "operationId": "get_webhook_afnor_flow_service_v1_webhooks__webhook_uid__get",
        "parameters": [
          {
            "name": "webhook_uid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Webhook Uid"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorWebhookItem"
                },
                "example": {
                  "webhookId": "wh_01HZX0F6N1B3KQAM7VV9G8T0YT",
                  "callbackUrl": "https://partner.example.com/afnor/callback",
                  "flowTypes": [
                    "CustomerInvoice"
                  ],
                  "flowDirection": "Out",
                  "ackStatus": "Ok"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request body (e.g. invalid `flowInfo` JSON, unknown `docType`, bad SHA-256).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the AFNOR Flow-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed AFNOR schema validation (FlowInfo, SearchFlowFilters, WebhookParams…).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (document_service / webhook_service / tx-doc) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "404": {
            "description": "Requested flow / webhook does not exist or is not visible to the calling organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "AFNOR Flow Service"
        ],
        "summary": "Update webhook technical params (updateWebhook)",
        "description": "Patch the *technical* callback parameters of an existing subscription — XP Z12-013\nv1.3.0 § 6.8 `updateWebhook`. Only `headers`, `authentication` and `signature` may be\nrotated; AFNOR explicitly forbids mutating `metadata` (flowType / flowDirection /\nackStatus) since that would silently change which events the partner receives.\n\nReturns **204 No Content** on success. Internal upstream errors are deliberately\nswallowed so the contract always honours the technical-only spec — partners can\nsafely retry the same PATCH idempotently.\n\n**Example request:**\n```json\n{\n  \"authentication\": {\"type\": \"bearer\", \"token\": \"new-secret\"},\n  \"headers\": [{\"name\": \"X-Partner-Key\", \"value\": \"rotated\"}]\n}\n```\n\n**Errors**\n\n| Status | Code                    | When                                              |\n|--------|-------------------------|---------------------------------------------------|\n| 400    | `BAD_REQUEST`       | Body attempts to mutate `metadata`.               |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                        |\n| 403    | `FORBIDDEN_ACCESS`             | `Organization-Id` not authorised.                 |\n| 404    | `NOT_FOUND`             | Webhook ID unknown.                               |\n| 422    | `UNPROCESSABLE_ENTITY`      | `WebhookPatchPayload` failed schema validation.   |\n| 429    | `TOO_MANY_REQUESTS`          | Update quota exhausted.                           |\n| 502    | `UPSTREAM_ERROR`        | Webhook store returned a non-2xx response.        |\n| 503    | `SERVICE_UNAVAILABLE`  | Webhook store unreachable.                        |",
        "operationId": "update_webhook_afnor_flow_service_v1_webhooks__webhook_uid__patch",
        "parameters": [
          {
            "name": "webhook_uid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Webhook Uid"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookPatchPayload"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Technical parameters updated — no response body."
          },
          "400": {
            "description": "Malformed request body (e.g. invalid `flowInfo` JSON, unknown `docType`, bad SHA-256).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the AFNOR Flow-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed AFNOR schema validation (FlowInfo, SearchFlowFilters, WebhookParams…).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (document_service / webhook_service / tx-doc) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "404": {
            "description": "Requested flow / webhook does not exist or is not visible to the calling organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "AFNOR Flow Service"
        ],
        "summary": "Delete webhook (deleteWebhook)",
        "description": "Unsubscribe a webhook — XP Z12-013 v1.3.0 § 6.9 `deleteWebhook`. The subscription is\nremoved synchronously; in-flight deliveries already on the retry queue are aborted.\nReturns **204 No Content** on success.\n\n**Errors**\n\n| Status | Code                    | When                                              |\n|--------|-------------------------|---------------------------------------------------|\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                        |\n| 403    | `FORBIDDEN_ACCESS`             | Webhook belongs to another organisation.          |\n| 404    | `NOT_FOUND`             | Webhook ID unknown or already deleted.            |\n| 422    | `UNPROCESSABLE_ENTITY`      | `webhook_uid` failed path validation.             |\n| 429    | `TOO_MANY_REQUESTS`          | Deletion quota exhausted.                         |\n| 502    | `UPSTREAM_ERROR`        | Webhook store returned a non-2xx response.        |\n| 503    | `SERVICE_UNAVAILABLE`  | Webhook store unreachable.                        |",
        "operationId": "delete_webhook_afnor_flow_service_v1_webhooks__webhook_uid__delete",
        "parameters": [
          {
            "name": "webhook_uid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Webhook Uid"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Subscription deleted — no further events will fire on this callback."
          },
          "400": {
            "description": "Malformed request body (e.g. invalid `flowInfo` JSON, unknown `docType`, bad SHA-256).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key valid but lacks the AFNOR Flow-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed AFNOR schema validation (FlowInfo, SearchFlowFilters, WebhookParams…).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream service (document_service / webhook_service / tx-doc) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream service unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "404": {
            "description": "Requested flow / webhook does not exist or is not visible to the calling organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/directory-service/v1/healthcheck": {
      "get": {
        "tags": [
          "AFNOR Directory Service"
        ],
        "summary": "Health check",
        "description": "Liveness probe required by AFNOR XP Z12-013 v1.3.0 § 7 (Directory-Service reachability).\n\nReturns a static `{\"status\": \"ok\"}` so partner PDPs can verify the Directory-Service\nfacade is reachable before exercising the SIREN / SIRET / routing-code endpoints.\nNo auth required; no upstream calls performed.\n\n**Example response (200):**\n```json\n{\"status\": \"ok\"}\n```\n\n**Errors**\n\n| Status | Code                   | When                              |\n|--------|------------------------|-----------------------------------|\n| 503    | `SERVICE_UNAVAILABLE`  | Process not yet ready / dying.    |",
        "operationId": "healthcheck_afnor_directory_service_v1_healthcheck_get",
        "responses": {
          "200": {
            "description": "Service is live.",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Healthcheck Afnor Directory Service V1 Healthcheck Get"
                },
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/directory-service/v1/siren/search": {
      "post": {
        "tags": [
          "AFNOR Directory Service"
        ],
        "summary": "Search companies by SIREN (searchCompanyBySiren)",
        "description": "Search French legal units by SIREN / business name — AFNOR XP Z12-013 v1.3.0 § 7.2\n`searchCompanyBySiren`. The route maps the AFNOR `filters` block to a Peppol\nDirectory query (`country=FR`, plus SIREN-as-`q` and the derived French VAT). When\nboth `siren` and `businessName` filters are supplied the SIREN takes precedence and\nthe name acts as a post-fetch substring filter.\n\nPagination uses `ignore` (offset) + `limit`. The handler fetches a larger window\nupstream so deep pages don't return empty incorrectly and `totalNumberOfResults`\nreflects the full match set.\n\n**Example request — exact SIREN:**\n```json\n{\n  \"filters\": {\"siren\": {\"op\": \"strict\", \"value\": \"921376265\"}},\n  \"limit\": 50,\n  \"ignore\": 0\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"search\": {\"filters\": {\"siren\": {\"op\": \"strict\", \"value\": \"921376265\"}}, \"limit\": 50, \"ignore\": 0},\n  \"totalNumberOfResults\": 1,\n  \"results\": [\n    {\n      \"siren\": \"921376265\",\n      \"businessName\": \"FLOWIE\",\n      \"entityType\": \"PrivateVatRegistered\",\n      \"administrativeStatus\": \"A\",\n      \"instructions\": {\"isSalesProspectingForbidden\": False}\n    }\n  ]\n}\n```\n\n**Example response (200 — empty result for unknown SIREN):**\n```json\n{\"search\": {\"filters\": {\"siren\": {\"value\": \"000000000\"}}}, \"totalNumberOfResults\": 0, \"results\": []}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                       |\n|--------|-------------------------|------------------------------------------------------------|\n| 400    | `BAD_REQUEST`       | SIREN not 9 digits, unsupported filter operator.           |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                                 |\n| 403    | `FORBIDDEN_ACCESS`             | Key lacks Directory-Service scope.                         |\n| 422    | `UNPROCESSABLE_ENTITY`      | `SirenSearchRequest` failed schema validation.             |\n| 429    | `TOO_MANY_REQUESTS`          | Search quota exhausted.                                    |\n| 502    | `UPSTREAM_ERROR`        | Peppol Directory / ppf-annuaire returned non-2xx.          |\n| 503    | `SERVICE_UNAVAILABLE`  | Peppol Directory / ppf-annuaire unreachable.               |",
        "operationId": "search_siren_afnor_directory_service_v1_siren_search_post",
        "parameters": [
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SirenSearchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Page of legal units matching the AFNOR filter set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SirenSearchResponse"
                },
                "example": {
                  "search": {
                    "filters": {
                      "siren": {
                        "op": "strict",
                        "value": "921376265"
                      }
                    },
                    "limit": 50,
                    "ignore": 0
                  },
                  "totalNumberOfResults": 1,
                  "results": [
                    {
                      "siren": "921376265",
                      "businessName": "FLOWIE",
                      "entityType": "PrivateVatRegistered",
                      "administrativeStatus": "A",
                      "instructions": {
                        "isSalesProspectingForbidden": false
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid filter (e.g. SIREN not 9 digits, SIRET not 14 digits, unknown country).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the AFNOR Directory-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path / query failed AFNOR schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream directory (Peppol Directory / ppf-annuaire / PPF) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream directory unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/directory-service/v1/siren/code-insee:{siren}": {
      "get": {
        "tags": [
          "AFNOR Directory Service"
        ],
        "summary": "Get company by SIREN (getCompanyBySiren)",
        "description": "Look up a single French legal unit by its 9-digit SIREN — AFNOR XP Z12-013 v1.3.0\n§ 7.3 `getCompanyBySiren`. The path parameter follows the AFNOR `code-insee:{siren}`\ntemplate; `fields` lets the caller project a subset of the response keys\n(`siren`, `businessName`, `entityType`, `administrativeStatus`, `instructions`,\n`peppolId`, `country`, `city`, `postalCode`).\n\n**Example request:**\n```\nGET /v1/siren/code-insee:921376265?fields=siren&fields=businessName\n```\n\n**Example response (200):**\n```json\n{\n  \"siren\": \"921376265\",\n  \"businessName\": \"FLOWIE\",\n  \"entityType\": \"PrivateVatRegistered\",\n  \"administrativeStatus\": \"A\",\n  \"instructions\": {\"isSalesProspectingForbidden\": false},\n  \"peppolId\": \"0009:921376265\",\n  \"country\": \"FR\",\n  \"city\": \"PARIS\",\n  \"postalCode\": \"75008\"\n}\n```\n\n**Example error (404):**\n```json\n{\"errorCode\": \"404\", \"errorMessage\": \"Company with SIREN 000000000 not found\"}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                |\n|--------|-------------------------|-----------------------------------------------------|\n| 400    | `BAD_REQUEST`       | SIREN is not 9 digits.                              |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                          |\n| 403    | `FORBIDDEN_ACCESS`             | Key lacks Directory-Service scope.                  |\n| 404    | `NOT_FOUND`             | SIREN not present in any backing directory.         |\n| 422    | `UNPROCESSABLE_ENTITY`      | Path parameter failed pattern validation.           |\n| 429    | `TOO_MANY_REQUESTS`          | Lookup quota exhausted.                             |\n| 502    | `UPSTREAM_ERROR`        | Peppol Directory / ppf-annuaire returned non-2xx.   |\n| 503    | `SERVICE_UNAVAILABLE`  | Peppol Directory / ppf-annuaire unreachable.        |",
        "operationId": "get_siren_afnor_directory_service_v1_siren_code_insee__siren__get",
        "parameters": [
          {
            "name": "siren",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^([0-9]{9})$",
              "description": "SIREN (9 digits)",
              "title": "Siren"
            },
            "description": "SIREN (9 digits)"
          },
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "title": "Fields"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Legal unit detail (`legalUnitPayloadHistory` shape, plus Peppol extension fields).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Get Siren Afnor Directory Service V1 Siren Code Insee  Siren  Get"
                },
                "example": {
                  "siren": "921376265",
                  "businessName": "FLOWIE",
                  "entityType": "PrivateVatRegistered",
                  "administrativeStatus": "A",
                  "instructions": {
                    "isSalesProspectingForbidden": false
                  },
                  "peppolId": "0009:921376265",
                  "country": "FR",
                  "city": "PARIS",
                  "postalCode": "75008"
                }
              }
            }
          },
          "400": {
            "description": "Invalid filter (e.g. SIREN not 9 digits, SIRET not 14 digits, unknown country).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the AFNOR Directory-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path / query failed AFNOR schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream directory (Peppol Directory / ppf-annuaire / PPF) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream directory unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "404": {
            "description": "Requested SIREN / SIRET / routing code does not exist in the backing directory.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/directory-service/v1/siret/search": {
      "post": {
        "tags": [
          "AFNOR Directory Service"
        ],
        "summary": "Search establishments by SIRET (searchFacilityBySiret)",
        "description": "Search French establishments by SIRET / SIREN / name — AFNOR XP Z12-013 v1.3.0 § 7.4\n`searchFacilityBySiret`. The handler picks the most specific filter available and\ndispatches to ppf-annuaire accordingly:\n\n1. Exact SIRET (14 digits) → `/api/siret/{siret}` — single establishment lookup.\n2. SIREN (9 digits) → `/api/siren/{siren}` — synthetic SIRET (`siren + 00001`).\n3. Name → `/api/search/name?q={name}` — synthetic SIRET per match.\n4. No usable filter → empty result.\n\nThe `administrativeStatus` field follows INSEE conventions (`A` = actif, `F` = fermé).\n\n**Example request — exact SIRET:**\n```json\n{\n  \"filters\": {\"siret\": {\"op\": \"strict\", \"value\": \"75297877500027\"}},\n  \"limit\": 50,\n  \"ignore\": 0\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"search\": {\"filters\": {\"siret\": {\"op\": \"strict\", \"value\": \"75297877500027\"}}, \"limit\": 50, \"ignore\": 0},\n  \"totalNumberOfResults\": 1,\n  \"results\": [\n    {\n      \"siret\": \"75297877500027\",\n      \"siren\": \"752978775\",\n      \"name\": \"FLOWIE SAS\",\n      \"facilityType\": \"P\",\n      \"administrativeStatus\": \"A\",\n      \"address\": {\n        \"addressLines\": [\"10 RUE DE LA PAIX\"],\n        \"postalCode\": \"75002\",\n        \"locality\": \"PARIS\",\n        \"country\": \"FR\"\n      },\n      \"siretInstructions\": {\"isSalesProspectingForbidden\": false}\n    }\n  ]\n}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                  |\n|--------|-------------------------|-------------------------------------------------------|\n| 400    | `BAD_REQUEST`       | SIRET not 14 digits, SIREN not 9 digits.              |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                            |\n| 403    | `FORBIDDEN_ACCESS`             | Key lacks Directory-Service scope.                    |\n| 422    | `UNPROCESSABLE_ENTITY`      | `SiretSearchRequest` failed schema validation.        |\n| 429    | `TOO_MANY_REQUESTS`          | Search quota exhausted.                               |\n| 502    | `UPSTREAM_ERROR`        | ppf-annuaire returned non-2xx.                        |\n| 503    | `SERVICE_UNAVAILABLE`  | ppf-annuaire unreachable.                             |",
        "operationId": "search_siret_afnor_directory_service_v1_siret_search_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SiretSearchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Page of establishments matching the AFNOR filter set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiretSearchResponse"
                },
                "example": {
                  "search": {
                    "filters": {
                      "siret": {
                        "op": "strict",
                        "value": "75297877500027"
                      }
                    },
                    "limit": 50,
                    "ignore": 0
                  },
                  "totalNumberOfResults": 1,
                  "results": [
                    {
                      "siret": "75297877500027",
                      "siren": "752978775",
                      "name": "FLOWIE SAS",
                      "facilityType": "P",
                      "administrativeStatus": "A",
                      "address": {
                        "addressLines": [
                          "10 RUE DE LA PAIX"
                        ],
                        "postalCode": "75002",
                        "locality": "PARIS",
                        "country": "FR"
                      },
                      "siretInstructions": {
                        "isSalesProspectingForbidden": false
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid filter (e.g. SIREN not 9 digits, SIRET not 14 digits, unknown country).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the AFNOR Directory-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path / query failed AFNOR schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream directory (Peppol Directory / ppf-annuaire / PPF) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream directory unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/directory-service/v1/siret/code-insee:{siret}": {
      "get": {
        "tags": [
          "AFNOR Directory Service"
        ],
        "summary": "Get establishment by SIRET (getFacilityBySiret)",
        "description": "Look up a single French establishment by its 14-digit SIRET — AFNOR XP Z12-013\nv1.3.0 § 7.5 `getFacilityBySiret`. The handler tries `/api/siret/{siret}` first; on\n404 it falls back to the parent SIREN (`/api/siren/{siret[:9]}`) and reuses that\ndata. In sandbox / test mode a synthetic establishment is returned so partners can\nrehearse the contract without depending on a real INSEE entry.\n\n`fields` projects the response to a subset of the AFNOR keys.\n\n**Example response (200):**\n```json\n{\n  \"siret\": \"75297877500027\",\n  \"siren\": \"752978775\",\n  \"name\": \"FLOWIE SAS\",\n  \"facilityType\": \"P\",\n  \"administrativeStatus\": \"A\",\n  \"address\": {\n    \"addressLines\": [\"10 RUE DE LA PAIX\"],\n    \"postalCode\": \"75002\",\n    \"locality\": \"PARIS\",\n    \"country\": \"FR\"\n  },\n  \"siretInstructions\": {\"isSalesProspectingForbidden\": false}\n}\n```\n\n**Example error (404):**\n```json\n{\"errorCode\": \"404\", \"errorMessage\": \"Establishment with SIRET 75297877599999 not found\"}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                |\n|--------|-------------------------|-----------------------------------------------------|\n| 400    | `BAD_REQUEST`       | SIRET is not 14 digits.                             |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                          |\n| 403    | `FORBIDDEN_ACCESS`             | Key lacks Directory-Service scope.                  |\n| 404    | `NOT_FOUND`             | SIRET (and parent SIREN) not in ppf-annuaire.       |\n| 422    | `UNPROCESSABLE_ENTITY`      | Path parameter failed pattern validation.           |\n| 429    | `TOO_MANY_REQUESTS`          | Lookup quota exhausted.                             |\n| 502    | `UPSTREAM_ERROR`        | ppf-annuaire returned non-2xx.                      |\n| 503    | `SERVICE_UNAVAILABLE`  | ppf-annuaire unreachable.                           |",
        "operationId": "get_siret_afnor_directory_service_v1_siret_code_insee__siret__get",
        "parameters": [
          {
            "name": "siret",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^([0-9]{14})$",
              "description": "SIRET (14 digits)",
              "title": "Siret"
            },
            "description": "SIRET (14 digits)"
          },
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "title": "Fields"
            }
          },
          {
            "name": "include",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "title": "Include"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Establishment detail (`facilityPayloadHistory` shape).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Get Siret Afnor Directory Service V1 Siret Code Insee  Siret  Get"
                },
                "example": {
                  "siret": "75297877500027",
                  "siren": "752978775",
                  "name": "FLOWIE SAS",
                  "facilityType": "P",
                  "administrativeStatus": "A",
                  "address": {
                    "addressLines": [
                      "10 RUE DE LA PAIX"
                    ],
                    "postalCode": "75002",
                    "locality": "PARIS",
                    "country": "FR"
                  },
                  "siretInstructions": {
                    "isSalesProspectingForbidden": false
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid filter (e.g. SIREN not 9 digits, SIRET not 14 digits, unknown country).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the AFNOR Directory-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path / query failed AFNOR schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream directory (Peppol Directory / ppf-annuaire / PPF) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream directory unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "404": {
            "description": "Requested SIREN / SIRET / routing code does not exist in the backing directory.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/directory-service/v1/routing-code/search": {
      "post": {
        "tags": [
          "AFNOR Directory Service"
        ],
        "summary": "Search routing codes (searchRoutingCode)",
        "description": "List the active routing codes published for a company — AFNOR XP Z12-013 v1.3.0\n§ 7.6 `searchRoutingCode`. The handler extracts the SIRET filter, derives the parent\nSIREN (first 9 digits), and queries ppf-annuaire's PA routing-plan endpoint\n(`/api/pa/{siren}`). Each routing plan entry is mapped to an AFNOR routing-code\nrecord (`routingIdentifier`, `routingCodeName`, `administrativeStatus`, `address`);\npass `include=[\"siret\",\"siren\"]` to embed those identifiers back into each row.\n\n**Example request:**\n```json\n{\n  \"filters\": {\"siret\": {\"op\": \"strict\", \"value\": \"75297877500027\"}},\n  \"include\": [\"siret\", \"siren\"],\n  \"limit\": 50\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"search\": {\"filters\": {\"siret\": {\"op\": \"strict\", \"value\": \"75297877500027\"}}, \"include\": [\"siret\", \"siren\"], \"limit\": 50},\n  \"totalNumberOfResults\": 1,\n  \"results\": [\n    {\n      \"routingIdentifier\": \"PDP-DCSNET\",\n      \"routingCodeName\": \"DCSnet PDP\",\n      \"administrativeStatus\": \"A\",\n      \"address\": {\n        \"addressLines\": [\"10 RUE DE LA PAIX\"],\n        \"postalCode\": \"75002\",\n        \"locality\": \"PARIS\",\n        \"country\": \"FR\"\n      },\n      \"siret\": \"75297877500027\",\n      \"siren\": \"752978775\"\n    }\n  ]\n}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                  |\n|--------|-------------------------|-------------------------------------------------------|\n| 400    | `BAD_REQUEST`       | SIRET shorter than 9 digits.                          |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                            |\n| 403    | `FORBIDDEN_ACCESS`             | Key lacks Directory-Service scope.                    |\n| 422    | `UNPROCESSABLE_ENTITY`      | `RoutingCodeSearchRequest` failed schema validation.  |\n| 429    | `TOO_MANY_REQUESTS`          | Search quota exhausted.                               |\n| 502    | `UPSTREAM_ERROR`        | ppf-annuaire PA endpoint returned non-2xx.            |\n| 503    | `SERVICE_UNAVAILABLE`  | ppf-annuaire PA endpoint unreachable.                 |",
        "operationId": "search_routing_code_afnor_directory_service_v1_routing_code_search_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RoutingCodeSearchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Routing plan entries for the company derived from the supplied SIRET.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoutingCodeSearchResponse"
                },
                "example": {
                  "search": {
                    "filters": {
                      "siret": {
                        "op": "strict",
                        "value": "75297877500027"
                      }
                    },
                    "limit": 50
                  },
                  "totalNumberOfResults": 1,
                  "results": [
                    {
                      "routingIdentifier": "PDP-DCSNET",
                      "routingCodeName": "DCSnet PDP",
                      "administrativeStatus": "A",
                      "address": {
                        "addressLines": [
                          "10 RUE DE LA PAIX"
                        ],
                        "postalCode": "75002",
                        "locality": "PARIS",
                        "country": "FR"
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid filter (e.g. SIREN not 9 digits, SIRET not 14 digits, unknown country).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the AFNOR Directory-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path / query failed AFNOR schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream directory (Peppol Directory / ppf-annuaire / PPF) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream directory unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/directory-service/v1/routing-code/siret:{siret}/code:{routing_identifier}": {
      "get": {
        "tags": [
          "AFNOR Directory Service"
        ],
        "summary": "Get routing code (getRoutingCodeBySiretAndId)",
        "description": "Resolve a specific routing code for a company — AFNOR XP Z12-013 v1.3.0 § 7.7\n`getRoutingCodeBySiretAndId`. The handler fetches the full PA routing plan via\nppf-annuaire (`/api/pa/{siren}` where `siren = siret[:9]`), then filters down to the\nentry whose `routingIdentifier` matches the path parameter. In sandbox / test mode\na synthetic Flowie Sandbox Access Point is synthesised so any (siret, routing_id)\npair round-trips successfully.\n\n**Example request:**\n```\nGET /v1/routing-code/siret:75297877500027/code:PDP-DCSNET?include=siret\n```\n\n**Example response (200):**\n```json\n{\n  \"routingIdentifier\": \"PDP-DCSNET\",\n  \"routingCodeName\": \"DCSnet PDP\",\n  \"administrativeStatus\": \"A\",\n  \"address\": {\n    \"addressLines\": [\"10 RUE DE LA PAIX\"],\n    \"postalCode\": \"75002\",\n    \"locality\": \"PARIS\",\n    \"country\": \"FR\"\n  },\n  \"siret\": \"75297877500027\"\n}\n```\n\n**Example error (404 — non-sandbox key, unknown identifier):**\n```json\n{\"errorCode\": \"404\", \"errorMessage\": \"Routing code UNKNOWN-PA not found for SIRET 75297877500027\"}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                |\n|--------|-------------------------|-----------------------------------------------------|\n| 400    | `BAD_REQUEST`       | Path parameters malformed.                          |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                          |\n| 403    | `FORBIDDEN_ACCESS`             | Key lacks Directory-Service scope.                  |\n| 404    | `NOT_FOUND`             | No routing plan for SIRET, or identifier unknown.   |\n| 422    | `UNPROCESSABLE_ENTITY`      | Path / query failed schema validation.              |\n| 429    | `TOO_MANY_REQUESTS`          | Lookup quota exhausted.                             |\n| 502    | `UPSTREAM_ERROR`        | ppf-annuaire PA endpoint returned non-2xx.          |\n| 503    | `SERVICE_UNAVAILABLE`  | ppf-annuaire PA endpoint unreachable.               |",
        "operationId": "get_routing_code_afnor_directory_service_v1_routing_code_siret__siret__code__routing_identifier__get",
        "parameters": [
          {
            "name": "siret",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "SIRET (14 digits)",
              "title": "Siret"
            },
            "description": "SIRET (14 digits)"
          },
          {
            "name": "routing_identifier",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Routing identifier (max 100 chars)",
              "title": "Routing Identifier"
            },
            "description": "Routing identifier (max 100 chars)"
          },
          {
            "name": "include",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "title": "Include"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "title": "Fields"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Routing code detail matching `siret` + `routing_identifier`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Get Routing Code Afnor Directory Service V1 Routing Code Siret  Siret  Code  Routing Identifier  Get"
                },
                "example": {
                  "routingIdentifier": "PDP-DCSNET",
                  "routingCodeName": "DCSnet PDP",
                  "administrativeStatus": "A",
                  "address": {
                    "addressLines": [
                      "10 RUE DE LA PAIX"
                    ],
                    "postalCode": "75002",
                    "locality": "PARIS",
                    "country": "FR"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid filter (e.g. SIREN not 9 digits, SIRET not 14 digits, unknown country).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the AFNOR Directory-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path / query failed AFNOR schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream directory (Peppol Directory / ppf-annuaire / PPF) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream directory unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "404": {
            "description": "Requested SIREN / SIRET / routing code does not exist in the backing directory.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/directory-service/v1/directory-line/search": {
      "post": {
        "tags": [
          "AFNOR Directory Service"
        ],
        "summary": "Search directory lines (searchDirectoryLine)",
        "description": "Search directory lines (reception points) for a company — AFNOR XP Z12-013 v1.3.0\n§ 7.8 `searchDirectoryLine`. The AFNOR filter set (`filters` / `fields` / `ignore`)\nis forwarded to ppf-annuaire's `/api/search/ligne-annuaire`, which proxies the\nFrench PPF `/ligne-annuaire/recherche` endpoint. Each returned `ligne` is mapped to\nthe AFNOR directory-line shape (`addressingIdentifier`, `routingIdentifier`, `siret`,\n`administrativeStatus`, `recipientManagement`, `address`).\n\n`ignore` is forwarded server-side so each page is fetched at the source instead of\nover-fetching and slicing locally. `fields` projects the response keys after mapping.\n\n**Example request:**\n```json\n{\n  \"filters\": {\"siret\": {\"op\": \"strict\", \"value\": \"75297877500027\"}},\n  \"sorting\": [{\"field\": \"addressingIdentifier\", \"order\": \"ascending\"}],\n  \"fields\": [\"addressingIdentifier\", \"routingIdentifier\"],\n  \"limit\": 100,\n  \"ignore\": 0\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"search\": {\"filters\": {\"siret\": {\"op\": \"strict\", \"value\": \"75297877500027\"}}, \"limit\": 100, \"ignore\": 0},\n  \"totalNumberOfResults\": 1,\n  \"results\": [\n    {\n      \"addressingIdentifier\": \"75297877500027_001\",\n      \"directoryLineStatus\": \"Enabled\",\n      \"siren\": \"752978775\",\n      \"siret\": \"75297877500027\",\n      \"routingIdentifier\": \"PDP-DCSNET\"\n    }\n  ]\n}\n```\n\n**Example response (200 — empty result):**\n```json\n{\"search\": {\"filters\": {}}, \"totalNumberOfResults\": 0, \"results\": []}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                  |\n|--------|-------------------------|-------------------------------------------------------|\n| 400    | `BAD_REQUEST`       | Filter values not recognised by PPF (malformed SIRET).|\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                            |\n| 403    | `FORBIDDEN_ACCESS`             | Key lacks Directory-Service scope.                    |\n| 422    | `UNPROCESSABLE_ENTITY`      | `DirectoryLineSearchRequest` failed schema validation.|\n| 429    | `TOO_MANY_REQUESTS`          | Search quota exhausted.                               |\n| 502    | `UPSTREAM_ERROR`        | ppf-annuaire / PPF returned non-2xx.                  |\n| 503    | `SERVICE_UNAVAILABLE`  | ppf-annuaire / PPF unreachable.                       |",
        "operationId": "search_directory_line_afnor_directory_service_v1_directory_line_search_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DirectoryLineSearchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Directory lines (reception points / `lignes annuaire`) for the company.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectoryLineSearchResponse"
                },
                "example": {
                  "search": {
                    "filters": {
                      "siret": {
                        "op": "strict",
                        "value": "75297877500027"
                      }
                    },
                    "limit": 100,
                    "ignore": 0
                  },
                  "totalNumberOfResults": 1,
                  "results": [
                    {
                      "addressingIdentifier": "75297877500027_001",
                      "directoryLineStatus": "Enabled",
                      "siren": "752978775",
                      "siret": "75297877500027",
                      "routingIdentifier": "PDP-DCSNET",
                      "platformType": "WK"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid filter (e.g. SIREN not 9 digits, SIRET not 14 digits, unknown country).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the AFNOR Directory-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path / query failed AFNOR schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream directory (Peppol Directory / ppf-annuaire / PPF) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream directory unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/afnor/directory-service/v1/directory-line/code:{addressing_identifier}": {
      "get": {
        "tags": [
          "AFNOR Directory Service"
        ],
        "summary": "Get directory line by id (getDirectoryLineById)",
        "description": "Resolve a single directory line by its addressing identifier — AFNOR XP Z12-013\nv1.3.0 § 7.9 `getDirectoryLineById`. Backed by the same ppf-annuaire\n`/api/search/ligne-annuaire` (PISTE `/ligne-annuaire/recherche`) endpoint as\n`searchDirectoryLine`, filtered on the addressing identifier and reduced to the\nexact match. In sandbox / test mode a synthetic line is returned so partners can\nrehearse the contract.\n\n**Example request:**\n```\nGET /v1/directory-line/code:752978775_75297877500027_100003\n```\n\n**Example error (404):**\n```json\n{\"errorCode\": \"404\", \"errorMessage\": \"Directory line ... not found\"}\n```\n\n**Errors**\n\n| Status | Code                    | When                                                |\n|--------|-------------------------|-----------------------------------------------------|\n| 400    | `BAD_REQUEST`       | Addressing identifier malformed.                    |\n| 401    | `MISSING_TOKEN`          | Missing / invalid API key.                          |\n| 403    | `FORBIDDEN_ACCESS`             | Key lacks Directory-Service scope.                  |\n| 404    | `NOT_FOUND`             | No directory line for this addressing identifier.   |\n| 422    | `UNPROCESSABLE_ENTITY`      | Path parameter failed schema validation.            |\n| 429    | `TOO_MANY_REQUESTS`          | Lookup quota exhausted.                             |\n| 502    | `UPSTREAM_ERROR`        | ppf-annuaire / PPF returned non-2xx.                |\n| 503    | `SERVICE_UNAVAILABLE`  | ppf-annuaire / PPF unreachable.                     |",
        "operationId": "get_directory_line_afnor_directory_service_v1_directory_line_code__addressing_identifier__get",
        "parameters": [
          {
            "name": "addressing_identifier",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 125,
              "description": "Addressing identifier",
              "title": "Addressing Identifier"
            },
            "description": "Addressing identifier"
          },
          {
            "name": "include",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "title": "Include"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "title": "Fields"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Directory line detail (`directoryLinePayloadLegalUnitFacilityRoutingCode` shape).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Get Directory Line Afnor Directory Service V1 Directory Line Code  Addressing Identifier  Get"
                },
                "example": {
                  "addressingIdentifier": "752978775_75297877500027_100003",
                  "directoryLineStatus": "Enabled",
                  "siren": "752978775",
                  "siret": "75297877500027",
                  "routingIdentifier": "100003",
                  "platformType": "WK"
                }
              }
            }
          },
          "400": {
            "description": "Invalid filter (e.g. SIREN not 9 digits, SIRET not 14 digits, unknown country).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the AFNOR Directory-Service scope, or `Organization-Id` not authorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "422": {
            "description": "Request body / path / query failed AFNOR schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "429": {
            "description": "Per-PDP rate limit exceeded — retry after `Retry-After` seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream directory (Peppol Directory / ppf-annuaire / PPF) returned a non-2xx response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "503": {
            "description": "Upstream directory unavailable / timed out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          },
          "404": {
            "description": "Requested SIREN / SIRET / routing code does not exist in the backing directory.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AfnorError"
                }
              }
            }
          }
        }
      }
    },
    "/document/callback": {
      "post": {
        "tags": [
          "Document Callbacks"
        ],
        "summary": "cXML PunchOutOrderMessage callback (BrowserFormPost)",
        "description": "Receive a PunchOutOrderMessage from a supplier after catalog checkout.\n\nThis endpoint is called by the supplier's system (e.g. Lyreco) when\nthe user finishes shopping. The cXML body contains the cart items, the\nuploaded document is sent to the OCR pipeline which parses cXML and\ncreates a purchase request inside the buyer's Flowie organization.\n\n**PUBLIC endpoint — no API key / bearer token required.** Authentication\nis performed against the cXML body: a ``<SharedSecret>`` under\n``<Header>`` is matched against the supplier whitelist; if no shared\nsecret is present we fall back to matching the ``<From/Credential>`` or\n``<Sender/Credential>`` domain+identity (e.g. ``DUNS / 465585586`` for\nLyreco Spain). The ``<BuyerCookie>`` (a Flowie-issued UUID embedded in\nthe Setup Request as ``flowie:{org_id}:{thread_id?}:{nonce}``) provides\nthe second factor binding the request to a specific organization.\n\nThe request body is the raw cXML. Content-types accepted:\n\n* ``application/xml`` / ``text/xml`` — raw cXML.\n* ``application/x-www-form-urlencoded`` with field ``cxml-urlencoded``\n  (URL-encoded cXML) or ``cxml-base64`` — the BrowserFormPost envelope\n  (cXML 1.2.060 §6.1.2). Both are unwrapped before parsing.\n\nThe response is intentionally HTML (not the cXML ``<Response>`` body\nthe spec describes): BrowserFormPost makes the user's **browser** the\nHTTP client, so we return a meta-refresh page that lands the user back\nin their originating AI chat thread / org dashboard. Suppliers only\ncare that we return 2xx.\n\n**Example request:**\n```\nPOST /document/callback HTTP/1.1\nContent-Type: application/xml\n```\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE cXML SYSTEM \"http://xml.cxml.org/schemas/cXML/1.2.044/cXML.dtd\">\n<cXML payloadID=\"1718614200@flowie.fr\" timestamp=\"2026-06-17T08:30:00+00:00\">\n  <Header>\n    <From><Credential domain=\"DUNS\"><Identity>465585586</Identity></Credential></From>\n    <To><Credential domain=\"DUNS\"><Identity>FLOWIE</Identity></Credential></To>\n    <Sender>\n      <Credential domain=\"DUNS\">\n        <Identity>465585586</Identity>\n        <SharedSecret>PWD465585586</SharedSecret>\n      </Credential>\n      <UserAgent>Lyreco PunchOut</UserAgent>\n    </Sender>\n  </Header>\n  <Message>\n    <PunchOutOrderMessage>\n      <BuyerCookie>flowie:019c76b6-5ad7-7000-b52b-61a9ad3a47c8:thr_01H8YQ:nonce</BuyerCookie>\n      <PunchOutOrderMessageHeader operationAllowed=\"create\">\n        <Total><Money currency=\"EUR\">123.45</Money></Total>\n      </PunchOutOrderMessageHeader>\n      <ItemIn quantity=\"2\">…</ItemIn>\n    </PunchOutOrderMessage>\n  </Message>\n</cXML>\n```\n\n**Example response (200 — happy path):**\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta http-equiv=\"refresh\" content=\"0; url=https://app.flowie.me/acme/ai/chat/thr_01H8YQ\">\n    <title>Redirecting to Flowie…</title>\n  </head>\n  <body><h1>Cart received — returning to your conversation…</h1></body>\n</html>\n```\n\n**Example response (200 — upstream upload failed):**\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<cXML payloadID=\"...@flowie.fr\" timestamp=\"2026-06-17T08:30:00+00:00\">\n  <Response><Status code=\"500\" text=\"Processing error: …\"/></Response>\n</cXML>\n```\n\n**Errors**\n\n| Status | Code                 | When                                                                          |\n|--------|----------------------|-------------------------------------------------------------------------------|\n| 400    | `invalid_request`    | Empty body, or `<cXML>` failed to parse (`lxml.XMLSyntaxError`).              |\n| 401    | `invalid_credentials`| No matching `<SharedSecret>` and supplier-identity fallback also failed.      |",
        "operationId": "receive_punchout_cart_document_callback_post",
        "responses": {
          "200": {
            "description": "Cart accepted (or upload errored — failures still return 200 with a cXML <Status code=\"500\"/> body so the supplier doesn't retry-loop).",
            "content": {
              "application/json": {
                "schema": {}
              },
              "text/html": {
                "example": "<!DOCTYPE html><html lang=\"en\"><head><meta http-equiv=\"refresh\" content=\"0; url=https://app.flowie.me/acme/ai/chat/thr_01H8YQ\"><title>Redirecting to Flowie…</title></head><body><div class=\"card\"><h1>Cart received — returning to your conversation…</h1></div></body></html>"
              },
              "text/xml": {
                "example": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<cXML payloadID=\"…@flowie.fr\" timestamp=\"2026-06-17T08:30:00+00:00\">\n  <Response><Status code=\"500\" text=\"Processing error: …\"/></Response>\n</cXML>"
              }
            }
          },
          "400": {
            "description": "Empty body or malformed cXML.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Invalid XML"
                }
              }
            }
          },
          "401": {
            "description": "SharedSecret missing/unknown and supplier identity fallback failed.",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Invalid SharedSecret"
                }
              }
            }
          }
        }
      }
    },
    "/document/oci-callback": {
      "get": {
        "tags": [
          "Document Callbacks"
        ],
        "summary": "OCI cart callback (GET variant — supplier auto-submit)",
        "description": "Receive an OCI cart return.\n\nAuth model: the supplier-facing HOOK_URL must contain a ``flowie_cookie``\nquery parameter (or a ``flowie_cookie`` form field) carrying the agents-hub\nBuyerCookie ``flowie:{org_id}:{thread_id_or_empty}:{nonce}``. We use it to\nroute the cart to the right org and to redirect the user back into their\nchat thread, identical to the cXML callback's behaviour.\n\n**PUBLIC endpoint — no API key / bearer token required.** The\n``flowie_cookie`` is the authentication factor; without it the request\nis rejected with 400.\n\nBody is parsed as an OCI form: each ``NEW_ITEM-<FIELD>[n]`` field is one\nattribute of one cart line. Mandatory per-line fields are\n``DESCRIPTION`` / ``QUANTITY`` / ``PRICE`` / ``CURRENCY``; everything\nelse (UNIT, VENDORMAT, MATNR, MATGROUP, CONTRACT, SERVICE…) is optional.\n\n**Example request:**\n```\nPOST /document/oci-callback HTTP/1.1\nContent-Type: application/x-www-form-urlencoded\n\nflowie_cookie=flowie:019c76b6-5ad7-7000-b52b-61a9ad3a47c8:thr_01H8YQ:nonce\n&NEW_ITEM-DESCRIPTION[1]=A4+Copy+paper+80gsm\n&NEW_ITEM-QUANTITY[1]=10\n&NEW_ITEM-UNIT[1]=BX\n&NEW_ITEM-PRICE[1]=24.50\n&NEW_ITEM-PRICEUNIT[1]=1\n&NEW_ITEM-CURRENCY[1]=EUR\n&NEW_ITEM-VENDORMAT[1]=LYR-A4-80\n```\n\n**Example response (200):**\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head><meta http-equiv=\"refresh\" content=\"0; url=https://app.flowie.me/acme/ai/chat/thr_01H8YQ\"></head>\n  <body><h1>Cart received — returning to your conversation…</h1></body>\n</html>\n```\n\n**Example response (400 — missing cookie):**\n```json\n{\"detail\": \"Missing or invalid flowie_cookie\"}\n```\n\n**Errors**\n\n| Status | Code               | When                                                            |\n|--------|--------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`  | `flowie_cookie` missing or org segment unparseable.             |",
        "operationId": "receive_oci_cart_document_oci_callback_get",
        "responses": {
          "200": {
            "description": "Cart received and uploaded — browser is redirected back to the originating Flowie chat / dashboard.",
            "content": {
              "application/json": {
                "schema": {}
              },
              "text/html": {
                "example": "<!DOCTYPE html><html lang=\"en\"><head><meta http-equiv=\"refresh\" content=\"0; url=https://app.flowie.me/acme/ai/chat/thr_01H8YQ\"><title>Redirecting to Flowie…</title></head><body><div class=\"card\"><h1>Cart received — returning to your conversation…</h1></div></body></html>"
              }
            }
          },
          "400": {
            "description": "Missing or invalid `flowie_cookie` (no org context).",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Missing or invalid flowie_cookie"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Document Callbacks"
        ],
        "summary": "OCI cart callback (Mercateo / Conrad / SAP-style suppliers)",
        "description": "Receive an OCI cart return.\n\nAuth model: the supplier-facing HOOK_URL must contain a ``flowie_cookie``\nquery parameter (or a ``flowie_cookie`` form field) carrying the agents-hub\nBuyerCookie ``flowie:{org_id}:{thread_id_or_empty}:{nonce}``. We use it to\nroute the cart to the right org and to redirect the user back into their\nchat thread, identical to the cXML callback's behaviour.\n\n**PUBLIC endpoint — no API key / bearer token required.** The\n``flowie_cookie`` is the authentication factor; without it the request\nis rejected with 400.\n\nBody is parsed as an OCI form: each ``NEW_ITEM-<FIELD>[n]`` field is one\nattribute of one cart line. Mandatory per-line fields are\n``DESCRIPTION`` / ``QUANTITY`` / ``PRICE`` / ``CURRENCY``; everything\nelse (UNIT, VENDORMAT, MATNR, MATGROUP, CONTRACT, SERVICE…) is optional.\n\n**Example request:**\n```\nPOST /document/oci-callback HTTP/1.1\nContent-Type: application/x-www-form-urlencoded\n\nflowie_cookie=flowie:019c76b6-5ad7-7000-b52b-61a9ad3a47c8:thr_01H8YQ:nonce\n&NEW_ITEM-DESCRIPTION[1]=A4+Copy+paper+80gsm\n&NEW_ITEM-QUANTITY[1]=10\n&NEW_ITEM-UNIT[1]=BX\n&NEW_ITEM-PRICE[1]=24.50\n&NEW_ITEM-PRICEUNIT[1]=1\n&NEW_ITEM-CURRENCY[1]=EUR\n&NEW_ITEM-VENDORMAT[1]=LYR-A4-80\n```\n\n**Example response (200):**\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head><meta http-equiv=\"refresh\" content=\"0; url=https://app.flowie.me/acme/ai/chat/thr_01H8YQ\"></head>\n  <body><h1>Cart received — returning to your conversation…</h1></body>\n</html>\n```\n\n**Example response (400 — missing cookie):**\n```json\n{\"detail\": \"Missing or invalid flowie_cookie\"}\n```\n\n**Errors**\n\n| Status | Code               | When                                                            |\n|--------|--------------------|-----------------------------------------------------------------|\n| 400    | `invalid_request`  | `flowie_cookie` missing or org segment unparseable.             |",
        "operationId": "receive_oci_cart_document_oci_callback_post",
        "responses": {
          "200": {
            "description": "Cart received and uploaded — browser is redirected back to the originating Flowie chat / dashboard.",
            "content": {
              "application/json": {
                "schema": {}
              },
              "text/html": {
                "example": "<!DOCTYPE html><html lang=\"en\"><head><meta http-equiv=\"refresh\" content=\"0; url=https://app.flowie.me/acme/ai/chat/thr_01H8YQ\"><title>Redirecting to Flowie…</title></head><body><div class=\"card\"><h1>Cart received — returning to your conversation…</h1></div></body></html>"
              }
            }
          },
          "400": {
            "description": "Missing or invalid `flowie_cookie` (no org context).",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Missing or invalid flowie_cookie"
                }
              }
            }
          }
        }
      }
    },
    "/v1/oauth/scopes": {
      "get": {
        "tags": [
          "OAuth"
        ],
        "summary": "Public scope catalogue (no auth required)",
        "description": "Return every grantable scope with a human-readable description.\n\nPublic — no auth required. Agents call this once at boot to render an\nhonest scope-selection UI to the user before kicking off the consent\nflow at ``POST /v1/oauth/authorize``.\n\n**Example request:**\n```\nGET /v1/oauth/scopes\n```\n\n**Example response (200):**\n```json\n{\n  \"scopes\": [\n    {\"scope\": \"send\", \"label\": \"Send documents\",\n     \"description\": \"Issue invoices, credit notes, orders over Peppol.\"},\n    {\"scope\": \"documents.read\", \"label\": \"Read documents\",\n     \"description\": \"List, search, download XML / PDF / structured views of documents.\"}\n  ]\n}\n```\n\n**Errors**\n\n| Status | Code                   | When                                                  |\n|--------|------------------------|-------------------------------------------------------|\n| 429    | `rate_limited`         | Too many requests — retry after `Retry-After` seconds.|\n| 503    | `upstream_unavailable` | Upstream service unavailable.                         |",
        "operationId": "get_scope_catalogue_v1_oauth_scopes_get",
        "responses": {
          "200": {
            "description": "The full list of grantable scopes plus human-readable labels.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScopeCatalogueResponse"
                },
                "example": {
                  "scopes": [
                    {
                      "scope": "send",
                      "label": "Send documents",
                      "description": "Issue invoices, credit notes, orders over Peppol."
                    },
                    {
                      "scope": "receive",
                      "label": "Receive documents",
                      "description": "Configure inbound Peppol delivery + webhooks + SMP registration."
                    },
                    {
                      "scope": "documents.read",
                      "label": "Read documents",
                      "description": "List, search, download XML / PDF / structured views of documents."
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (sandbox bootstrap is capped at 120/IP/hr).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream sandbox / api-keys service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/oauth/authorize": {
      "post": {
        "tags": [
          "OAuth"
        ],
        "summary": "Step 1 of the consent flow — register intent, get a consent URL",
        "description": "Step 1 of the consent flow. Returns the URL the agent shows the user.\n\nThe agent supplies its display name, the scopes it wants, and a PKCE\nchallenge (SHA-256 of a verifier it keeps secret). The user opens\n``consent_url`` in their browser, clicks Approve, and the server hands\nthem a short-lived code that the agent later exchanges via\n``POST /v1/oauth/token``.\n\n**Example request:**\n```json\nPOST /v1/oauth/authorize\n{\n  \"client_name\": \"Claude Desktop · Acme\",\n  \"scopes\": [\"send\", \"documents.read\"],\n  \"redirect_uri\": \"urn:ietf:wg:oauth:2.0:oob\",\n  \"code_challenge\": \"E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM\",\n  \"code_challenge_method\": \"S256\",\n  \"state\": \"xyz-session-binding\"\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"request_id\": \"cnsnt_019a6e5b3b4c7000a460a09181acc257\",\n  \"consent_url\": \"https://exchange.flowie.fr/oauth/consent?req=cnsnt_…\",\n  \"expires_in\": 600\n}\n```\n\n**Errors**\n\n| Status | Code                   | When                                                       |\n|--------|------------------------|------------------------------------------------------------|\n| 400    | `invalid_request`      | Unknown scope, redirect URI not allowed, or bad PKCE.      |\n| 422    | `validation_error`     | Body failed schema validation.                             |\n| 429    | `rate_limited`         | Too many requests — retry after `Retry-After` seconds.     |\n| 503    | `upstream_unavailable` | Upstream sandbox / api-keys service unavailable.           |",
        "operationId": "authorize_v1_oauth_authorize_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuthorizeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Consent request created — show `consent_url` to the user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthorizeResponse"
                },
                "example": {
                  "request_id": "cnsnt_019a6e5b3b4c7000a460a09181acc257",
                  "consent_url": "https://exchange.flowie.fr/oauth/consent?req=cnsnt_019a6e5b3b4c7000a460a09181acc257",
                  "expires_in": 600
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. unknown scope, invalid PKCE verifier, expired code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (sandbox bootstrap is capped at 120/IP/hr).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream sandbox / api-keys service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/oauth/token": {
      "post": {
        "tags": [
          "OAuth"
        ],
        "summary": "Exchange the consent auth code (with PKCE) for an API key",
        "description": "Final step of the consent flow — exchange the auth code for an API key.\n\nThe server hashes ``code_verifier`` with SHA-256 and checks it against the\n``code_challenge`` recorded during ``/authorize``. The code is one-time\nand expires 5 minutes after consent.\n\n**Example request:**\n```json\nPOST /v1/oauth/token\n{\n  \"grant_type\": \"authorization_code\",\n  \"code\": \"code_01H8YQXM2V7K5N3R4T6W8Z1A2B\",\n  \"code_verifier\": \"dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\"\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"access_token\": \"flw_test_01H8YQXM2V7K5N3R4T6W8Z1B9CdEfGhIjKlMnOpQrStUv\",\n  \"token_type\": \"Bearer\",\n  \"scopes\": [\"send\", \"documents.read\"],\n  \"expires_in\": 604800,\n  \"company_id\": \"cmp_01H8YQXM2V7K5N3R4T6W8Z1A2B\",\n  \"organization_id\": \"org_sbx_01H8YQXM2V7K5N3R4T6W8Z1A2B\"\n}\n```\n\n**Errors**\n\n| Status | Code                   | When                                                                  |\n|--------|------------------------|-----------------------------------------------------------------------|\n| 400    | `invalid_grant`        | Code unknown / already redeemed / expired, or PKCE verifier mismatch. |\n| 422    | `validation_error`     | Body failed schema validation.                                        |\n| 429    | `rate_limited`         | Too many requests — retry after `Retry-After` seconds.                |\n| 503    | `upstream_unavailable` | Upstream api-keys service unavailable.                                |",
        "operationId": "token_v1_oauth_token_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Code validated — the API key is issued and bound to the consent's organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                },
                "example": {
                  "access_token": "flw_test_01H8YQXM2V7K5N3R4T6W8Z1B9CdEfGhIjKlMnOpQrStUv",
                  "token_type": "Bearer",
                  "scopes": [
                    "send",
                    "documents.read"
                  ],
                  "expires_in": 604800,
                  "company_id": "cmp_01H8YQXM2V7K5N3R4T6W8Z1A2B",
                  "organization_id": "org_sbx_01H8YQXM2V7K5N3R4T6W8Z1A2B"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. unknown scope, invalid PKCE verifier, expired code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (sandbox bootstrap is capped at 120/IP/hr).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream sandbox / api-keys service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/oauth/handoff": {
      "post": {
        "tags": [
          "OAuth"
        ],
        "summary": "Generate a pre-approved, single-use link to share with an AI agent",
        "description": "Generate a single-use, pre-approved link to share with an AI agent.\n\nThe agent reads the URL, calls ``POST /v1/oauth/handoff/exchange`` with\nthe embedded token, and gets a scoped API key bound to **your**\norganization. Skips the consent dance for agents you already trust.\n\nScope rule: you can only pre-approve scopes your own token already\nholds. Live keys (``mode=live``) require a paid tier.\n\n**Example request:**\n```json\nPOST /v1/oauth/handoff\nAuthorization: Bearer flw_live_…\n{\n  \"scopes\": [\"send\", \"documents.read\"],\n  \"label\": \"Claude Desktop — June onboarding\",\n  \"ttl_seconds\": 600,\n  \"mode\": \"test\"\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"handoff_token\": \"hnd_01H8YQXM2V7K5N3R4T6W8Z1A2B3C4D5E6F\",\n  \"handoff_url\": \"https://exchange.flowie.fr/oauth/handoff?token=hnd_…\",\n  \"expires_at\": \"2026-06-17T08:30:00+00:00\",\n  \"scopes\": [\"send\", \"documents.read\"],\n  \"organization_id\": \"019c76b2-9c94-7000-8cb6-ef104afb6093\"\n}\n```\n\n**Errors**\n\n| Status | Code                   | When                                                                  |\n|--------|------------------------|-----------------------------------------------------------------------|\n| 400    | `invalid_request`      | Requested a scope the caller doesn't hold, or live mode on free tier. |\n| 401    | `unauthorized`         | Missing / invalid `Authorization` header or API key.                  |\n| 403    | `forbidden`            | Key valid but cannot grant handoffs.                                  |\n| 422    | `validation_error`     | Body failed schema validation.                                        |\n| 429    | `rate_limited`         | Too many requests — retry after `Retry-After` seconds.                |\n| 503    | `upstream_unavailable` | Upstream api-keys service unavailable.                                |",
        "operationId": "create_handoff_v1_oauth_handoff_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HandoffCreateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Handoff URL minted — share it with the agent; it expires after `ttl_seconds`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HandoffCreateResponse"
                },
                "example": {
                  "handoff_token": "hnd_01H8YQXM2V7K5N3R4T6W8Z1A2B3C4D5E6F",
                  "handoff_url": "https://exchange.flowie.fr/oauth/handoff?token=hnd_01H8YQXM2V7K5N3R4T6W8Z1A2B3C4D5E6F",
                  "expires_at": "2026-06-17T08:30:00+00:00",
                  "scopes": [
                    "send",
                    "receive",
                    "documents.read",
                    "companies.read",
                    "stats"
                  ],
                  "organization_id": "019c76b2-9c94-7000-8cb6-ef104afb6093"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. scope not held by caller, live mode but free tier).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but the requested scope is forbidden for it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream api-keys service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/oauth/handoff/sandbox": {
      "post": {
        "tags": [
          "OAuth"
        ],
        "summary": "Anonymous sandbox handoff — bootstrap a fresh org + mint a handoff token",
        "description": "Anonymous handoff: bootstraps a fresh sandbox + mints a handoff token.\n\nNo auth required. Subject to the same 120/IP/hr rate limit as\n``POST /v1/sandbox/bootstrap``. Designed for the docs home page to\nauto-mint a personalized URL on every visit so an LLM that fetches\nthe URL can redeem the embedded token straight away.\n\nThe redeemed key is bound to a brand-new sandbox organization\n(``org_sbx_…``) — never to a real production tenant.\n\n**Example request:**\n```\nPOST /v1/oauth/handoff/sandbox\n```\n\n**Example response (200):**\n```json\n{\n  \"handoff_token\": \"hnd_01H8YQXM2V7K5N3R4T6W8Z1A2B3C4D5E6F\",\n  \"handoff_url\": \"https://exchange.flowie.fr/oauth/handoff?token=hnd_…\",\n  \"expires_at\": \"2026-06-17T08:30:00+00:00\",\n  \"scopes\": [\"send\", \"receive\", \"documents.read\", \"companies.read\", \"stats\"],\n  \"organization_id\": \"org_sbx_01H8YQXM2V7K5N3R4T6W8Z1A2B\"\n}\n```\n\n**Example response (429 — IP cap reached):**\n```json\n{\n  \"type\": \"rate_limit_error\",\n  \"code\": \"BOOTSTRAP_RATE_LIMITED\",\n  \"message\": \"Sandbox handoff is limited to 120 calls per IP per hour (shared with /v1/sandbox/bootstrap). Retry in 1734s.\",\n  \"retryAfter\": 1734\n}\n```\n\n**Errors**\n\n| Status | Code                       | When                                                       |\n|--------|----------------------------|------------------------------------------------------------|\n| 400    | `invalid_request`          | Malformed request (rare for this endpoint).                |\n| 429    | `BOOTSTRAP_RATE_LIMITED`   | 120/IP/hr cap reached — honour `Retry-After`.              |\n| 503    | `upstream_unavailable`     | Sandbox bootstrap upstream unavailable.                    |",
        "operationId": "create_sandbox_handoff_v1_oauth_handoff_sandbox_post",
        "responses": {
          "200": {
            "description": "A new sandbox org was provisioned and a single-use handoff URL was issued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HandoffCreateResponse"
                },
                "example": {
                  "handoff_token": "hnd_01H8YQXM2V7K5N3R4T6W8Z1A2B3C4D5E6F",
                  "handoff_url": "https://exchange.flowie.fr/oauth/handoff?token=hnd_01H8YQXM2V7K5N3R4T6W8Z1A2B3C4D5E6F",
                  "expires_at": "2026-06-17T08:30:00+00:00",
                  "scopes": [
                    "send",
                    "receive",
                    "documents.read",
                    "companies.read",
                    "stats"
                  ],
                  "organization_id": "org_sbx_01H8YQXM2V7K5N3R4T6W8Z1A2B"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. unknown scope, invalid PKCE verifier, expired code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (sandbox bootstrap is capped at 120/IP/hr).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream sandbox / api-keys service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/oauth/handoff/exchange": {
      "post": {
        "tags": [
          "OAuth"
        ],
        "summary": "Redeem a handoff token for an API key (single-use, no auth)",
        "description": "Redeem a handoff token for an API key. Single-use, no other auth.\n\nTokens minted by ``POST /v1/oauth/handoff`` (or the anonymous\n``/handoff/sandbox`` variant) can be redeemed exactly once. A second\nattempt returns ``400 invalid_grant``.\n\n**Example request:**\n```json\nPOST /v1/oauth/handoff/exchange\n{\n  \"handoff_token\": \"hnd_01H8YQXM2V7K5N3R4T6W8Z1A2B3C4D5E6F\"\n}\n```\n\n**Example response (200):**\n```json\n{\n  \"access_token\": \"flw_test_01H8YQXM2V7K5N3R4T6W8Z1B9CdEfGhIjKlMnOpQrStUv\",\n  \"token_type\": \"Bearer\",\n  \"scopes\": [\"send\", \"receive\", \"documents.read\", \"companies.read\", \"stats\"],\n  \"expires_in\": 604800,\n  \"company_id\": \"cmp_01H8YQXM2V7K5N3R4T6W8Z1A2B\",\n  \"organization_id\": \"019c76b2-9c94-7000-8cb6-ef104afb6093\"\n}\n```\n\n**Errors**\n\n| Status | Code                   | When                                                       |\n|--------|------------------------|------------------------------------------------------------|\n| 400    | `invalid_grant`        | Token unknown / already redeemed / expired.                |\n| 422    | `validation_error`     | Body failed schema validation.                             |\n| 429    | `rate_limited`         | Too many requests — retry after `Retry-After` seconds.     |\n| 503    | `upstream_unavailable` | Upstream api-keys service unavailable.                     |",
        "operationId": "exchange_handoff_v1_oauth_handoff_exchange_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HandoffExchangeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Token redeemed — the issued API key is returned and tied to the handoff's org.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                },
                "example": {
                  "access_token": "flw_test_01H8YQXM2V7K5N3R4T6W8Z1B9CdEfGhIjKlMnOpQrStUv",
                  "token_type": "Bearer",
                  "scopes": [
                    "send",
                    "documents.read"
                  ],
                  "expires_in": 604800,
                  "company_id": "cmp_01H8YQXM2V7K5N3R4T6W8Z1A2B",
                  "organization_id": "org_sbx_01H8YQXM2V7K5N3R4T6W8Z1A2B"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request (e.g. unknown scope, invalid PKCE verifier, expired code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (sandbox bootstrap is capped at 120/IP/hr).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Upstream sandbox / api-keys service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sandbox/bootstrap": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Self-serve a fresh sandbox API key + starter company (no auth)",
        "description": "Issue a fresh sandbox API key, a starter sandbox company, and a Peppol\ntest identifier — all in one call. **No authentication required.**\n\nDesigned for the \"I just landed on the docs and want to try the API\"\ncase. The returned `apiKey` is the full secret — store it now, it will\nnot be shown again. Bootstrapped keys expire after 7 days; create a\nlong-lived one from the dashboard later. Rate-limited per IP (default\n120 calls / hour). Set `keyType=platform` or `keyType=white_label` to\nmint a key that satisfies the platform-key gate in sandbox.\n\n---\n\n**Example request:**\n```bash\ncurl -X POST https://api.flowie.fr/v1/sandbox/bootstrap \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"label\": \"quickstart\", \"email\": \"dev@example.com\", \"keyType\": \"personal\"}'\n```\n\n**Example 200 response:**\n```json\n{\n  \"organizationId\": \"org_sbx_4f8a1c2d3e7b9a5c6d8e0f1a2b3c\",\n  \"apiKey\": \"flw_test_4f8a1c2d3e7b9a5c6d8e0f1a2b3c4d5e6f7a8b9c0d1e2f3a\",\n  \"keyPrefix\": \"flw_test_4f8a1c2d\",\n  \"keyType\": \"personal\",\n  \"company\": {\n    \"id\": \"comp_sbx_4f8a1c2d3e7b9a5c6d8e\",\n    \"peppolId\": \"0208:0000000001\",\n    \"vatNumber\": \"BE0000000001\",\n    \"name\": \"Sandbox Test BVBA\",\n    \"country\": \"BE\",\n    \"status\": \"active\"\n  },\n  \"expiresAt\": \"2026-06-24T09:14:22.157894+00:00\",\n  \"nextSteps\": [\"Save the apiKey now — it will not be shown again.\", \"…\"],\n  \"docs\": {\"playground\": \"https://docs.get-flowie.com/playground/index.html\"}\n}\n```\n\n**Example 429 response — per-IP cap hit:**\n```json\n{\n  \"type\": \"rate_limit_error\",\n  \"code\": \"BOOTSTRAP_RATE_LIMITED\",\n  \"message\": \"Bootstrap is limited to 120 keys per IP per hour. Retry in 1843s, or contact developers@flowie.fr if you need more.\",\n  \"retryAfter\": 1843\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code                       | When                                                                |\n|--------|----------------------------|---------------------------------------------------------------------|\n| 422    | `validation_error`         | Body failed Pydantic validation (e.g. invalid `keyType`).           |\n| 429    | `BOOTSTRAP_RATE_LIMITED`   | Per-IP cap exhausted — `Retry-After` seconds before next attempt.   |\n| 500    | `internal_error`           | Persistence layer error while issuing the key.                      |",
        "operationId": "bootstrap_v1_sandbox_bootstrap_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SandboxBootstrapRequest",
                "default": {
                  "label": "quickstart",
                  "keyType": "personal"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sandbox key issued. The `apiKey` field is the only chance to capture the secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxBootstrapResponse"
                },
                "example": {
                  "organizationId": "org_sbx_4f8a1c2d3e7b9a5c6d8e0f1a2b3c",
                  "apiKey": "flw_test_4f8a1c2d3e7b9a5c6d8e0f1a2b3c4d5e6f7a8b9c0d1e2f3a",
                  "keyPrefix": "flw_test_4f8a1c2d",
                  "keyType": "personal",
                  "company": {
                    "id": "comp_sbx_4f8a1c2d3e7b9a5c6d8e",
                    "peppolId": "0208:0000000001",
                    "vatNumber": "BE0000000001",
                    "name": "Sandbox Test BVBA",
                    "country": "BE",
                    "status": "active"
                  },
                  "expiresAt": "2026-06-24T09:14:22.157894+00:00",
                  "nextSteps": [
                    "Save the apiKey now — it will not be shown again.",
                    "Open the playground at https://docs.get-flowie.com/playground/index.html",
                    "Try POST /v1/directory/verify with peppolId=\"0208:TEST_OK\".",
                    "Then POST /v1/documents/send to that recipient.",
                    "Listen for document.delivered on a webhook (use ngrok for local)."
                  ],
                  "docs": {
                    "playground": "https://docs.get-flowie.com/playground/index.html",
                    "reference": "https://docs.get-flowie.com/reference/index.html",
                    "sandbox": "https://docs.get-flowie.com/sandbox/index.html",
                    "fixtures": "https://docs.get-flowie.com/fixtures/"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Per-IP bootstrap cap exhausted (default 120 / hour). `Retry-After` header set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while issuing the sandbox key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sandbox/reset": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Wipe sandbox events / idempotency cache for the caller",
        "description": "Wipe events and / or idempotency cache for the caller's organization.\n\nRequires a **test-mode** API key. The literal string `\"yes\"` in\n`confirm` is mandatory to prevent accidental wipes mid-debug. Use\n`scope` to narrow the blast radius:\n\n* `all`         — events + idempotency + pending scheduled events (default)\n* `events`      — only the event stream\n* `idempotency` — only entries tied to the calling key\n* `documents`   — (reserved) no-op today; counter returns 0\n\n---\n\n**Example request:**\n```bash\ncurl -X POST https://api.flowie.fr/v1/sandbox/reset \\\n  -H \"Authorization: Bearer flw_test_…\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"confirm\": \"yes\", \"scope\": \"all\"}'\n```\n\n**Example response:**\n```json\n{\n  \"deletedDocuments\": 0,\n  \"deletedEvents\": 17,\n  \"deletedIdempotencyEntries\": 42,\n  \"organizationId\": \"org_sbx_4f8a1c2d3e7b9a5c6d8e0f1a2b3c\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code               | When                                                       |\n|--------|--------------------|------------------------------------------------------------|\n| 400    | `invalid_request`  | `scope` is not one of `all` / `events` / `idempotency`.    |\n| 401    | `unauthorized`     | Missing / invalid `Authorization` header.                  |\n| 403    | `SANDBOX_ONLY`     | Caller is using a live-mode key.                           |\n| 422    | `validation_error` | Body missing `confirm: \"yes\"`.                             |\n| 429    | `rate_limited`     | Too many requests — retry after `Retry-After`.             |",
        "operationId": "reset_sandbox_v1_sandbox_reset_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SandboxResetRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sandbox state wiped — counters reflect how many rows were deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxResetResponse"
                },
                "example": {
                  "deletedDocuments": 0,
                  "deletedEvents": 17,
                  "deletedIdempotencyEntries": 42,
                  "organizationId": "org_sbx_4f8a1c2d3e7b9a5c6d8e0f1a2b3c"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. unparsable `by` duration, unknown `scope`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Endpoint only callable with a test-mode (`flw_test_…`) API key — live keys are rejected with code `SANDBOX_ONLY`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while mutating sandbox state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sandbox/rate-limit/exhaust": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Force the caller's org into a 429-loop for N seconds",
        "description": "Arm a rate-limit override that makes every subsequent request from the\ncaller's sandbox org return `429` for `durationSeconds` (max 3600).\nRequires a **test-mode** API key.\n\nUseful for verifying your retry / exponential-backoff implementation\nunder realistic conditions — including responses that honor the\n`Retry-After` header.\n\n---\n\n**Example request:**\n```bash\ncurl -X POST https://api.flowie.fr/v1/sandbox/rate-limit/exhaust \\\n  -H \"Authorization: Bearer flw_test_…\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"durationSeconds\": 60}'\n```\n\n**Example response:**\n```json\n{\n  \"organizationId\": \"org_sbx_4f8a1c2d3e7b9a5c6d8e0f1a2b3c\",\n  \"durationSeconds\": 60,\n  \"expiresAt\": \"2026-06-17T09:15:22.157894+00:00\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code               | When                                                       |\n|--------|--------------------|------------------------------------------------------------|\n| 401    | `unauthorized`     | Missing / invalid `Authorization` header.                  |\n| 403    | `SANDBOX_ONLY`     | Caller is using a live-mode key.                           |\n| 422    | `validation_error` | `durationSeconds` outside [1, 3600].                       |\n| 429    | `rate_limited`     | Too many requests — retry after `Retry-After`.             |",
        "operationId": "exhaust_rate_limit_v1_sandbox_rate_limit_exhaust_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SandboxRateLimitExhaustRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Override armed — subsequent requests return 429 until `expiresAt`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxRateLimitExhaustResponse"
                },
                "example": {
                  "organizationId": "org_sbx_4f8a1c2d3e7b9a5c6d8e0f1a2b3c",
                  "durationSeconds": 60,
                  "expiresAt": "2026-06-17T09:15:22.157894+00:00"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. unparsable `by` duration, unknown `scope`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Endpoint only callable with a test-mode (`flw_test_…`) API key — live keys are rejected with code `SANDBOX_ONLY`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while mutating sandbox state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sandbox/clock/advance": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Fast-forward a sandbox company's virtual clock",
        "description": "Advance a single sandbox company's virtual clock by `by`. Requires a\n**test-mode** API key.\n\nAccepts compact units: `s|m|h|d|w|y` (e.g. `\"60d\"`, `\"2h\"`, `\"1y\"`).\nThe offset is **per-company** — other tenants in the same sandbox org\nare unaffected. Pending scheduled events whose virtual fire-time has\nnow passed are woken on the next scheduler tick (~1s).\n\n---\n\n**Example request:**\n```bash\ncurl -X POST https://api.flowie.fr/v1/sandbox/clock/advance \\\n  -H \"Authorization: Bearer flw_test_…\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"companyId\": \"comp_sbx_4f8a1c2d3e7b9a5c6d8e\", \"by\": \"60d\"}'\n```\n\n**Example response:**\n```json\n{\n  \"companyId\": \"comp_sbx_4f8a1c2d3e7b9a5c6d8e\",\n  \"offsetSeconds\": 5184000,\n  \"virtualNow\": \"2026-08-16T09:14:22.157894+00:00\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code               | When                                                       |\n|--------|--------------------|------------------------------------------------------------|\n| 400    | `invalid_request`  | `by` could not be parsed (missing unit, unknown unit, negative). |\n| 401    | `unauthorized`     | Missing / invalid `Authorization` header.                  |\n| 403    | `SANDBOX_ONLY`     | Caller is using a live-mode key.                           |\n| 422    | `validation_error` | Body missing `companyId` or `by`.                          |\n| 429    | `rate_limited`     | Too many requests — retry after `Retry-After`.             |",
        "operationId": "advance_clock_v1_sandbox_clock_advance_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SandboxClockAdvanceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Clock advanced; `virtualNow` reflects wall-clock + cumulative offset.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxClockResponse"
                },
                "example": {
                  "companyId": "comp_sbx_4f8a1c2d3e7b9a5c6d8e",
                  "offsetSeconds": 5184000,
                  "virtualNow": "2026-08-16T09:14:22.157894+00:00"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. unparsable `by` duration, unknown `scope`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Endpoint only callable with a test-mode (`flw_test_…`) API key — live keys are rejected with code `SANDBOX_ONLY`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while mutating sandbox state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sandbox/clock/reset": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Snap a sandbox company's virtual clock back to now",
        "description": "Snap a sandbox company's virtual clock back to wall-clock now (offset\nbecomes 0). Requires a **test-mode** API key. Use this between scenarios\nto start each test from a known time anchor.\n\n---\n\n**Example request:**\n```bash\ncurl -X POST https://api.flowie.fr/v1/sandbox/clock/reset \\\n  -H \"Authorization: Bearer flw_test_…\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"companyId\": \"comp_sbx_4f8a1c2d3e7b9a5c6d8e\"}'\n```\n\n**Example response:**\n```json\n{\n  \"companyId\": \"comp_sbx_4f8a1c2d3e7b9a5c6d8e\",\n  \"offsetSeconds\": 0,\n  \"virtualNow\": \"2026-06-17T09:14:22.157894+00:00\"\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code               | When                                                       |\n|--------|--------------------|------------------------------------------------------------|\n| 401    | `unauthorized`     | Missing / invalid `Authorization` header.                  |\n| 403    | `SANDBOX_ONLY`     | Caller is using a live-mode key.                           |\n| 422    | `validation_error` | Body missing `companyId`.                                  |\n| 429    | `rate_limited`     | Too many requests — retry after `Retry-After`.             |",
        "operationId": "reset_clock_v1_sandbox_clock_reset_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SandboxClockResetRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Offset cleared; `virtualNow` equals wall-clock now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxClockResponse"
                },
                "example": {
                  "companyId": "comp_sbx_4f8a1c2d3e7b9a5c6d8e",
                  "offsetSeconds": 0,
                  "virtualNow": "2026-06-17T09:14:22.157894+00:00"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. unparsable `by` duration, unknown `scope`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Endpoint only callable with a test-mode (`flw_test_…`) API key — live keys are rejected with code `SANDBOX_ONLY`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while mutating sandbox state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/sandbox/idempotency/flush": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Drop every idempotency entry stored for the calling key",
        "description": "Drop every idempotency-cache entry stored against the calling key.\nRequires a **test-mode** API key.\n\nLets you re-run the exact same request with the same `Idempotency-Key`\nheader and get a fresh execution rather than a cached replay — handy\nwhen iterating on payload shape or stubbing webhooks.\n\n---\n\n**Example request:**\n```bash\ncurl -X POST https://api.flowie.fr/v1/sandbox/idempotency/flush \\\n  -H \"Authorization: Bearer flw_test_…\"\n```\n\n**Example response:**\n```json\n{\n  \"organizationId\": \"org_sbx_4f8a1c2d3e7b9a5c6d8e0f1a2b3c\",\n  \"deletedEntries\": 27\n}\n```\n\n---\n\n**Errors** (response body follows `ErrorResponse`):\n\n| Status | Code               | When                                                       |\n|--------|--------------------|------------------------------------------------------------|\n| 401    | `unauthorized`     | Missing / invalid `Authorization` header.                  |\n| 403    | `SANDBOX_ONLY`     | Caller is using a live-mode key.                           |\n| 429    | `rate_limited`     | Too many requests — retry after `Retry-After`.             |\n| 500    | `internal_error`   | Database error while deleting cache entries.               |",
        "operationId": "flush_idempotency_v1_sandbox_idempotency_flush_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Idempotency cache cleared; `deletedEntries` reports how many rows were removed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxIdempotencyFlushResponse"
                },
                "example": {
                  "organizationId": "org_sbx_4f8a1c2d3e7b9a5c6d8e0f1a2b3c",
                  "deletedEntries": 27
                }
              }
            }
          },
          "400": {
            "description": "Invalid request payload (e.g. unparsable `by` duration, unknown `scope`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Endpoint only callable with a test-mode (`flw_test_…`) API key — live keys are rejected with code `SANDBOX_ONLY`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — see `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error while mutating sandbox state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/requests": {
      "get": {
        "tags": [
          "Requests"
        ],
        "summary": "List captured request logs for your organization",
        "description": "List captured request logs for your organization (newest first).\n\nCaptures every mutation (POST/PUT/PATCH/DELETE) and every error; successful\nGETs only when ``REQUEST_LOG_ALL`` is enabled server-side. Filter by ``apiKeyId``\nor ``userId`` to see all queries done by a given key / user. Returns\nlightweight summaries — fetch a single ``request_id`` for the full\nrequest/response.\n\n**Example request:**\n```\nGET /v1/requests?method=POST&status=502&limit=20\nAuthorization: Bearer flw_live_…\n```\n\n**Example response (200):**\n```json\n{\n  \"data\": [\n    {\n      \"requestId\": \"019a6e5b-3b4c-7000-a460-a09181acc257\",\n      \"organizationId\": \"019c76b2-9c94-7000-8cb6-ef104afb6093\",\n      \"apiKeyId\": \"ak_01H8YQXM2V7K5N3R4T6W8Z1B9C\",\n      \"userId\": null,\n      \"userEmail\": null,\n      \"method\": \"POST\",\n      \"path\": \"/exchange/v1/documents/send\",\n      \"statusCode\": 502,\n      \"durationMs\": 543,\n      \"createdAt\": \"2026-06-17T08:24:11.214000+00:00\"\n    }\n  ],\n  \"hasMore\": false,\n  \"cursor\": null\n}\n```\n\n**Errors**\n\n| Status | Code                   | When                                                       |\n|--------|------------------------|------------------------------------------------------------|\n| 400    | `invalid_request`      | Unparseable ISO datetime on `since` / `until`.             |\n| 401    | `unauthorized`         | Missing / invalid `Authorization` header or API key.       |\n| 403    | `forbidden`            | Key valid but cross-org access denied.                     |\n| 422    | `validation_error`     | `limit` out of range or wrong type.                        |\n| 429    | `rate_limited`         | Too many requests — retry after `Retry-After` seconds.     |\n| 503    | `upstream_unavailable` | Request-log database unavailable.                          |",
        "operationId": "list_requests_v1_requests_get",
        "parameters": [
          {
            "name": "method",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Method"
            }
          },
          {
            "name": "path",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Substring match on the request path",
              "title": "Path"
            },
            "description": "Substring match on the request path"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact HTTP status code",
              "title": "Status"
            },
            "description": "Exact HTTP status code"
          },
          {
            "name": "apiKeyId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only queries made by this API key id (for JWT auth this is the OAuth client id)",
              "title": "Apikeyid"
            },
            "description": "Only queries made by this API key id (for JWT auth this is the OAuth client id)"
          },
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only queries made by this user id (JWT auth)",
              "title": "Userid"
            },
            "description": "Only queries made by this user id (JWT auth)"
          },
          {
            "name": "organizationId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only queries owned by this organization id",
              "title": "Organizationid"
            },
            "description": "Only queries owned by this organization id"
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO datetime — logs created at/after",
              "title": "Since"
            },
            "description": "ISO datetime — logs created at/after"
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO datetime — logs created before",
              "title": "Until"
            },
            "description": "ISO datetime — logs created before"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of recent request-log summaries (newest first).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response List Requests V1 Requests Get"
                },
                "example": {
                  "data": [
                    {
                      "requestId": "019a6e5b-3b4c-7000-a460-a09181acc257",
                      "organizationId": "019c76b2-9c94-7000-8cb6-ef104afb6093",
                      "apiKeyId": "ak_01H8YQXM2V7K5N3R4T6W8Z1B9C",
                      "method": "POST",
                      "path": "/exchange/v1/documents/send",
                      "statusCode": 502,
                      "durationMs": 543,
                      "createdAt": "2026-06-17T08:24:11.214000+00:00"
                    },
                    {
                      "requestId": "019a6e5b-7f12-7000-b820-91c2ad0918aa",
                      "organizationId": "019c76b2-9c94-7000-8cb6-ef104afb6093",
                      "apiKeyId": "jwt",
                      "userId": "usr_01H8YQXM2V7K5N3R4T6W8Z1A2B",
                      "userEmail": "yann@flowie.fr",
                      "method": "PATCH",
                      "path": "/exchange/v1/documents/doc_01H8…/lifecycle",
                      "statusCode": 200,
                      "durationMs": 87,
                      "createdAt": "2026-06-17T08:23:55.001000+00:00"
                    }
                  ],
                  "hasMore": false,
                  "total": 2
                }
              }
            }
          },
          "400": {
            "description": "Bad query parameter (e.g. unparseable ISO datetime on `since`/`until`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but the targeted log belongs to another organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Query parameters failed schema validation (e.g. `limit` out of range).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Request log database unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/requests/summary": {
      "get": {
        "tags": [
          "Requests"
        ],
        "summary": "Per-API-key (or per-user) usage rollup",
        "description": "Per-API-key (or per-user) usage rollup for your organization.\n\nPowers an \"API activity\" view: who called the API, how many times, how many\nerrors, and when they were last seen — without paging through every log.\nUse ``by=user`` to group by JWT user (and surface their email) instead of\nby API-key id.\n\n**Example request:**\n```\nGET /v1/requests/summary?by=user&since=2026-06-01T00:00:00Z\nAuthorization: Bearer flw_live_…\n```\n\n**Example response (200, grouped by API key):**\n```json\n{\n  \"by\": \"apiKey\",\n  \"data\": [\n    {\n      \"apiKeyId\": \"ak_01H8YQXM2V7K5N3R4T6W8Z1B9C\",\n      \"totalRequests\": 4218,\n      \"errorRequests\": 17,\n      \"lastRequestAt\": \"2026-06-17T08:24:11.214000+00:00\"\n    }\n  ]\n}\n```\n\n**Example response (200, grouped by user):**\n```json\n{\n  \"by\": \"user\",\n  \"data\": [\n    {\n      \"userId\": \"usr_01H8YQXM2V7K5N3R4T6W8Z1A2B\",\n      \"userEmail\": \"yann@flowie.fr\",\n      \"totalRequests\": 311,\n      \"errorRequests\": 2,\n      \"lastRequestAt\": \"2026-06-17T08:23:55.001000+00:00\"\n    }\n  ]\n}\n```\n\n**Errors**\n\n| Status | Code                   | When                                                       |\n|--------|------------------------|------------------------------------------------------------|\n| 400    | `invalid_request`      | Unparseable ISO datetime on `since` / `until`.             |\n| 401    | `unauthorized`         | Missing / invalid `Authorization` header or API key.       |\n| 403    | `forbidden`            | Key valid but lacks access to organization logs.           |\n| 422    | `validation_error`     | `by` not one of `apiKey`/`user`.                           |\n| 429    | `rate_limited`         | Too many requests — retry after `Retry-After` seconds.     |\n| 503    | `upstream_unavailable` | Request-log database unavailable.                          |",
        "operationId": "usage_summary_v1_requests_summary_get",
        "parameters": [
          {
            "name": "by",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Group by 'apiKey', 'user', or 'org'",
              "default": "apiKey",
              "title": "By"
            },
            "description": "Group by 'apiKey', 'user', or 'org'"
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO datetime — logs created at/after",
              "title": "Since"
            },
            "description": "ISO datetime — logs created at/after"
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO datetime — logs created before",
              "title": "Until"
            },
            "description": "ISO datetime — logs created before"
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregated counts per API key (or per user) for the requested window.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Usage Summary V1 Requests Summary Get"
                },
                "example": {
                  "by": "apiKey",
                  "data": [
                    {
                      "apiKeyId": "ak_01H8YQXM2V7K5N3R4T6W8Z1B9C",
                      "totalRequests": 4218,
                      "errorRequests": 17,
                      "lastRequestAt": "2026-06-17T08:24:11.214000+00:00"
                    },
                    {
                      "apiKeyId": "jwt",
                      "totalRequests": 311,
                      "errorRequests": 2,
                      "lastRequestAt": "2026-06-17T08:23:55.001000+00:00"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad query parameter (e.g. unparseable ISO datetime on `since`/`until`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but the targeted log belongs to another organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Query parameters failed schema validation (e.g. `limit` out of range).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Request log database unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/requests/{request_id}": {
      "get": {
        "tags": [
          "Requests"
        ],
        "summary": "Fetch a single captured request/response envelope by X-Request-Id",
        "description": "Return a captured 4xx/5xx request envelope.\n\nAll secrets are redacted at capture time, so the body returned here is\nalways safe to share — paste a ``requestId`` into a Slack channel or\nSentry comment and your team can pull the same view. In sandbox mode an\nunknown ``request_id`` returns a synthesised envelope (``sandbox: true``)\nso the contract can be exercised without first triggering a real failure.\n\n**Example request:**\n```\nGET /v1/requests/019a6e5b-3b4c-7000-a460-a09181acc257\nAuthorization: Bearer flw_live_…\n```\n\n**Example response (200):**\n```json\n{\n  \"requestId\": \"019a6e5b-3b4c-7000-a460-a09181acc257\",\n  \"organizationId\": \"019c76b2-9c94-7000-8cb6-ef104afb6093\",\n  \"apiKeyId\": \"ak_01H8YQXM2V7K5N3R4T6W8Z1B9C\",\n  \"method\": \"POST\",\n  \"path\": \"/exchange/v1/documents/send\",\n  \"queryString\": null,\n  \"request\": {\n    \"headers\": {\n      \"content-type\": \"application/json\",\n      \"authorization\": \"Bearer flw_live_…(redacted)\"\n    },\n    \"body\": {\"type\": \"invoice\", \"from\": \"vat:FR26921376265\", \"to\": \"0208:0123456789\"}\n  },\n  \"response\": {\n    \"statusCode\": 502,\n    \"headers\": {\"content-type\": \"application/json\"},\n    \"body\": {\"type\": \"upstream_error\", \"code\": \"upstream_error\",\n             \"message\": \"Upstream Peppol AP refused the document\",\n             \"requestId\": \"019a6e5b-3b4c-7000-a460-a09181acc257\"}\n  },\n  \"durationMs\": 543,\n  \"userAgent\": \"flowie-python/1.4.2\",\n  \"clientIp\": \"203.0.113.42\",\n  \"createdAt\": \"2026-06-17T08:24:11.214000+00:00\",\n  \"viewerUrl\": \"https://docs.get-flowie.com/playground/requests.html?id=019a6e5b-…\"\n}\n```\n\n**Example response (404):**\n```json\n{\n  \"type\": \"not_found\",\n  \"code\": \"not_found\",\n  \"message\": \"No request log for 019a6e5b-3b4c-7000-a460-a09181acc257\",\n  \"requestId\": \"019a6e5b-7f12-7000-b820-91c2ad0918aa\"\n}\n```\n\n**Errors**\n\n| Status | Code                   | When                                                                  |\n|--------|------------------------|-----------------------------------------------------------------------|\n| 401    | `unauthorized`         | Missing / invalid `Authorization` header or API key.                  |\n| 403    | `forbidden`            | The log exists but belongs to a different organization.               |\n| 404    | `not_found`            | No request log captured for this id (non-sandbox keys only).          |\n| 429    | `rate_limited`         | Too many requests — retry after `Retry-After` seconds.                |\n| 503    | `upstream_unavailable` | Request-log database unavailable.                                     |",
        "operationId": "get_request_v1_requests__request_id__get",
        "parameters": [
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Request Id"
            }
          },
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full captured envelope, with secrets redacted at capture time.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "title": "Response Get Request V1 Requests  Request Id  Get"
                },
                "example": {
                  "requestId": "019a6e5b-3b4c-7000-a460-a09181acc257",
                  "organizationId": "019c76b2-9c94-7000-8cb6-ef104afb6093",
                  "apiKeyId": "ak_01H8YQXM2V7K5N3R4T6W8Z1B9C",
                  "method": "POST",
                  "path": "/exchange/v1/documents/send",
                  "request": {
                    "headers": {
                      "content-type": "application/json",
                      "authorization": "Bearer flw_live_…(redacted)",
                      "x-request-id": "019a6e5b-3b4c-7000-a460-a09181acc257"
                    },
                    "body": {
                      "type": "invoice",
                      "from": "vat:FR26921376265",
                      "to": "0208:0123456789",
                      "documentNumber": "INV-2026-00042"
                    }
                  },
                  "response": {
                    "statusCode": 502,
                    "headers": {
                      "content-type": "application/json"
                    },
                    "body": {
                      "type": "upstream_error",
                      "code": "upstream_error",
                      "message": "Upstream Peppol AP refused the document",
                      "requestId": "019a6e5b-3b4c-7000-a460-a09181acc257"
                    }
                  },
                  "durationMs": 543,
                  "userAgent": "flowie-python/1.4.2",
                  "clientIp": "203.0.113.42",
                  "createdAt": "2026-06-17T08:24:11.214000+00:00",
                  "viewerUrl": "https://docs.get-flowie.com/playground/requests.html?id=019a6e5b-3b4c-7000-a460-a09181acc257"
                }
              }
            }
          },
          "400": {
            "description": "Bad query parameter (e.g. unparseable ISO datetime on `since`/`until`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "API key is valid but the targeted log belongs to another organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Query parameters failed schema validation (e.g. `limit` out of range).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Request log database unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "No request log captured for this `request_id` (and not in sandbox mode).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/portability/messages": {
      "post": {
        "tags": [
          "Portability"
        ],
        "summary": "Build a normalised inter-PA portability message (subject + 18-field CSV)",
        "description": "Assemble the AIFE inter-PA message for a portability request.\n\nReturns the normalised `subject`, the 18-field `csv` (header + row) and a\n`dispatched` flag. Dispatch is gated by `PORTABILITY_DISPATCH_ENABLED`\n(default OFF), so by default this is a safe build/preview — nothing is\nemailed to a counterparty PA.\n\n**Wire format is a best guess** pending the AIFE 15/07 annex; the exact\nsubject grammar, CSV columns and status codes are centralised in\n`app/services/portability/channel.py`.",
        "operationId": "build_portability_message_v1_portability_messages_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortabilityMessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message built. `dispatched` is false unless dispatch is enabled and configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortabilityMessageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed message (bad subject grammar, wrong CSV column count, unknown state).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/portability/messages/parse": {
      "post": {
        "tags": [
          "Portability"
        ],
        "summary": "Parse an inbound inter-PA portability message",
        "description": "Parse a received inter-PA message back into structured fields.\n\nValidates the normalised subject grammar and, when a `csvRow` is supplied,\nthe 18-column CSV payload. A subject that does not match the grammar returns\n400 (the caller should dead-letter it rather than open a request).",
        "operationId": "parse_portability_message_v1_portability_messages_parse_post",
        "parameters": [
          {
            "name": "authorization",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "name": "X-Flowie-Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Flowie-Organization-Id"
            }
          },
          {
            "name": "Organization-Id",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Organization-Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortabilityParseRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Subject (and optional CSV row) parsed into structured fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortabilityParseResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed message (bad subject grammar, wrong CSV column count, unknown state).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key / bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AckDetail": {
        "properties": {
          "level": {
            "type": "string",
            "enum": [
              "Error",
              "Warning"
            ],
            "title": "Level"
          },
          "item": {
            "type": "string",
            "title": "Item"
          },
          "reasonCode": {
            "type": "string",
            "title": "Reasoncode"
          },
          "reasonMessage": {
            "type": "string",
            "title": "Reasonmessage"
          }
        },
        "type": "object",
        "required": [
          "level",
          "item",
          "reasonCode",
          "reasonMessage"
        ],
        "title": "AckDetail",
        "description": "Single acknowledgement detail line (AcknowledgementDetail)."
      },
      "AckRequest": {
        "properties": {
          "eventIds": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Eventids"
          }
        },
        "type": "object",
        "required": [
          "eventIds"
        ],
        "title": "AckRequest"
      },
      "ActionRequest": {
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "mark-read",
              "mark-unread",
              "archive",
              "unarchive",
              "tag",
              "untag",
              "assign",
              "unassign",
              "add-note",
              "link"
            ],
            "title": "Action"
          },
          "tag": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tag"
          },
          "userId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Userid"
          },
          "note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Note"
          },
          "relatedDocumentId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Relateddocumentid"
          }
        },
        "type": "object",
        "required": [
          "action"
        ],
        "title": "ActionRequest"
      },
      "Address": {
        "properties": {
          "id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Id",
            "description": "Address UUID in org-v2"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "Optional label (e.g. 'HQ', 'Warehouse 2')"
          },
          "street": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Street"
          },
          "streetLine2": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Streetline2"
          },
          "city": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "City"
          },
          "state": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "State",
            "description": "State / province / region name"
          },
          "region": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Region",
            "description": "Alias of state — kept for backward compat"
          },
          "postalCode": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 20
              },
              {
                "type": "null"
              }
            ],
            "title": "Postalcode"
          },
          "country": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2,
                "minLength": 2,
                "pattern": "^[A-Z]{2}$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country",
            "description": "ISO 3166-1 alpha-2 country code"
          },
          "latitude": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Latitude"
          },
          "longitude": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Longitude"
          },
          "isDefaultShipping": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isdefaultshipping"
          },
          "isDefaultBilling": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isdefaultbilling"
          },
          "instructions": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Instructions"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "updatedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedat"
          }
        },
        "type": "object",
        "title": "Address",
        "description": "Postal address — mirrors org-v2 Address with backward-compatible field names.",
        "examples": [
          {
            "city": "ARNAS",
            "country": "FR",
            "id": "019a6e5b-3b4c-7000-a460-a09181acc257",
            "isDefaultBilling": true,
            "isDefaultShipping": false,
            "postalCode": "69400",
            "street": "891 ROUTE DES FRENES",
            "streetLine2": "Z.I.DE JOUX ARNAS NORD"
          }
        ]
      },
      "AfnorError": {
        "properties": {
          "errorCode": {
            "type": "string",
            "title": "Errorcode"
          },
          "errorMessage": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Errormessage"
          },
          "type": {
            "type": "string",
            "title": "Type",
            "default": "about:blank"
          },
          "details": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Details"
          },
          "instance": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Instance"
          }
        },
        "type": "object",
        "required": [
          "errorCode"
        ],
        "title": "AfnorError",
        "description": "RFC 7807-style problem detail (AFNOR Error schema)."
      },
      "AfnorWebhookCreated": {
        "properties": {
          "webhookId": {
            "type": "string",
            "title": "Webhookid"
          },
          "signingKey": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Signingkey"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          }
        },
        "type": "object",
        "required": [
          "webhookId"
        ],
        "title": "AfnorWebhookCreated",
        "description": "WebhookIdParam — 201 response body of createWebhook.\n\nPer the AFNOR swagger `WebhookIdParam`: ``{webhookId, signingKey, createdAt}``.\n``signingKey`` is the secret used to verify the HMAC signature of callbacks."
      },
      "AfnorWebhookItem": {
        "properties": {
          "webhookId": {
            "type": "string",
            "title": "Webhookid"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "callbackUrl": {
            "type": "string",
            "title": "Callbackurl"
          },
          "flowTypes": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flowtypes"
          },
          "flowDirection": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flowdirection"
          },
          "ackStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ackstatus"
          }
        },
        "type": "object",
        "required": [
          "webhookId",
          "callbackUrl"
        ],
        "title": "AfnorWebhookItem",
        "description": "Webhook (= WebhookIdParam + WebhookParams) — item in listWebhooks / getWebhook.\n\n``signingKey`` is intentionally OMITTED from list/get payloads: it is only\nreturned once at creation time, and all WebhookIdParam fields are optional in\nthe swagger, so leaving it out stays conformant while avoiding leaking the\nsecret on every read."
      },
      "AfnorWebhookList": {
        "properties": {
          "count": {
            "type": "integer",
            "title": "Count"
          },
          "webhooks": {
            "items": {
              "$ref": "#/components/schemas/AfnorWebhookItem"
            },
            "type": "array",
            "title": "Webhooks"
          }
        },
        "type": "object",
        "required": [
          "count",
          "webhooks"
        ],
        "title": "AfnorWebhookList",
        "description": "WebhookListResponse — 200 response body of listWebhooks."
      },
      "ApiKeyCreateRequest": {
        "properties": {
          "companyId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Companyid"
          },
          "name": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Name"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Scopes",
            "default": []
          },
          "expiresAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expiresat"
          },
          "rateLimit": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ratelimit"
          }
        },
        "type": "object",
        "required": [
          "name"
        ],
        "title": "ApiKeyCreateRequest"
      },
      "ApiKeyCreateResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "key": {
            "type": "string",
            "title": "Key"
          },
          "keyPrefix": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Keyprefix"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Scopes",
            "default": []
          },
          "companyId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Companyid"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "expiresAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expiresat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "key",
          "name"
        ],
        "title": "ApiKeyCreateResponse",
        "description": "Same as ApiKeyResponse but includes the full key (shown only once)."
      },
      "ApiKeyResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "keyPrefix": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Keyprefix"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Scopes",
            "default": []
          },
          "companyId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Companyid"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "expiresAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expiresat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "title": "ApiKeyResponse"
      },
      "AuthorizeRequest": {
        "properties": {
          "client_name": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Client Name",
            "description": "Display name shown on the consent page (e.g. 'Claude Desktop · Acme')."
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "minItems": 1,
            "title": "Scopes",
            "description": "Requested scopes — must all be in the public catalogue."
          },
          "redirect_uri": {
            "type": "string",
            "title": "Redirect Uri",
            "description": "Where to redirect with the auth code. Default = out-of-band (code shown on screen).",
            "default": "urn:ietf:wg:oauth:2.0:oob"
          },
          "code_challenge": {
            "type": "string",
            "maxLength": 128,
            "minLength": 43,
            "title": "Code Challenge",
            "description": "Base64URL(SHA256(code_verifier)) — RFC 7636 PKCE."
          },
          "code_challenge_method": {
            "type": "string",
            "const": "S256",
            "title": "Code Challenge Method",
            "description": "Only S256 is supported. ``plain`` is intentionally rejected.",
            "default": "S256"
          },
          "state": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "State",
            "description": "Opaque value the agent gets back on redirect — use it to bind the code to the session."
          }
        },
        "type": "object",
        "required": [
          "client_name",
          "scopes",
          "code_challenge"
        ],
        "title": "AuthorizeRequest",
        "description": "Step 1 — agent registers its consent intent.\n\nResponse carries a ``consent_url`` the agent must show to the user."
      },
      "AuthorizeResponse": {
        "properties": {
          "request_id": {
            "type": "string",
            "title": "Request Id",
            "description": "Server-side handle for this consent request."
          },
          "consent_url": {
            "type": "string",
            "title": "Consent Url",
            "description": "URL the agent shows to the user."
          },
          "expires_in": {
            "type": "integer",
            "title": "Expires In",
            "description": "Seconds until the request expires (consent must complete inside this window)."
          }
        },
        "type": "object",
        "required": [
          "request_id",
          "consent_url",
          "expires_in"
        ],
        "title": "AuthorizeResponse"
      },
      "BatchLifecycleUpdateRequest": {
        "properties": {
          "updates": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array",
            "title": "Updates"
          }
        },
        "type": "object",
        "required": [
          "updates"
        ],
        "title": "BatchLifecycleUpdateRequest"
      },
      "BatchSendItem": {
        "properties": {
          "idempotencyKey": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Idempotencykey"
          },
          "type": {
            "type": "string",
            "enum": [
              "invoice",
              "credit-note",
              "debit-note",
              "purchase-order",
              "purchase-request",
              "sales-order",
              "quote",
              "event"
            ],
            "title": "Type"
          },
          "format": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "json",
                  "ubl-xml",
                  "cii-xml",
                  "auto",
                  "raw"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Format"
          },
          "from": {
            "type": "string",
            "title": "From",
            "description": "Sender company (required). Accepts `0208:…` / `peppol:…` / `vat:…` / `comp_…` / `org:…`; normalised to the canonical Peppol id. For a multi-org caller it also selects the owning organization."
          },
          "to": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "To",
            "description": "Recipient. A Peppol id (`0208:…`/`peppol:…`) used as-is, or any resolvable identifier (`vat:`/`siren:`/`siret:`/`duns:`/`gln:`/`lei:`/`eori:`/`email:`/`domain:`/`name:`/`org:` or their bare forms). Omit for `type=event`."
          },
          "document": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DocumentBody"
              },
              {
                "type": "null"
              }
            ]
          },
          "xml": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Xml"
          },
          "file": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FileAttachment"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "type": "object",
        "required": [
          "type",
          "from"
        ],
        "title": "BatchSendItem"
      },
      "BatchSendRequest": {
        "properties": {
          "documents": {
            "items": {
              "$ref": "#/components/schemas/BatchSendItem"
            },
            "type": "array",
            "title": "Documents"
          }
        },
        "type": "object",
        "required": [
          "documents"
        ],
        "title": "BatchSendRequest"
      },
      "BatchSendResponse": {
        "properties": {
          "results": {
            "items": {},
            "type": "array",
            "title": "Results"
          },
          "summary": {
            "additionalProperties": true,
            "type": "object",
            "title": "Summary"
          }
        },
        "type": "object",
        "required": [
          "results",
          "summary"
        ],
        "title": "BatchSendResponse"
      },
      "Body_create_flow_afnor_flow_service_v1_flows_post": {
        "properties": {
          "flowInfo": {
            "type": "string",
            "title": "Flowinfo",
            "description": "JSON-encoded FlowInfo object"
          },
          "file": {
            "anyOf": [
              {
                "type": "string",
                "contentMediaType": "application/octet-stream"
              },
              {
                "type": "null"
              }
            ],
            "title": "File"
          }
        },
        "type": "object",
        "required": [
          "flowInfo"
        ],
        "title": "Body_create_flow_afnor_flow_service_v1_flows_post"
      },
      "CallbackParams": {
        "properties": {
          "url": {
            "type": "string",
            "title": "Url"
          },
          "headers": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Headers"
          },
          "authentication": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Authentication"
          },
          "signature": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Signature"
          }
        },
        "type": "object",
        "required": [
          "url"
        ],
        "title": "CallbackParams",
        "description": "CallbackParameters for webhook creation/update."
      },
      "CompanyComplianceItem": {
        "properties": {
          "companyId": {
            "type": "string",
            "title": "Companyid"
          },
          "vatNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatnumber"
          },
          "peppolId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Peppolid"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status"
          },
          "smpRegistered": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Smpregistered"
          },
          "smpRegisteredAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Smpregisteredat"
          },
          "compliance": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Compliance"
          },
          "lastCheckedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lastcheckedat"
          }
        },
        "type": "object",
        "required": [
          "companyId"
        ],
        "title": "CompanyComplianceItem"
      },
      "CompanyCreate": {
        "properties": {
          "vatNumber": {
            "type": "string",
            "maxLength": 20,
            "minLength": 4,
            "pattern": "^[A-Z]{2}[A-Z0-9]+$",
            "title": "Vatnumber",
            "description": "VAT number with country prefix (e.g. FR86797978996)"
          },
          "name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "address": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ]
          },
          "additionalIdentifiers": {
            "anyOf": [
              {
                "items": {},
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Additionalidentifiers"
          },
          "capabilities": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Capabilities"
          },
          "settings": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Settings"
          },
          "compliance": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Compliance"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          }
        },
        "type": "object",
        "required": [
          "vatNumber"
        ],
        "title": "CompanyCreate",
        "examples": [
          {
            "address": {
              "city": "Paris",
              "country": "FR",
              "postalCode": "75001",
              "street": "123 Rue de la Paix"
            },
            "name": "Acme SAS",
            "vatNumber": "FR86797978996"
          }
        ]
      },
      "CompanyImportBatchRequest": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/CompanyImportRequest"
            },
            "type": "array",
            "maxItems": 500,
            "minItems": 1,
            "title": "Items"
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "CompanyImportBatchRequest",
        "description": "Body for POST /v1/companies/import/batch — import many Sovos companies.\n\nEach item is a full ``CompanyImportRequest``. Items are imported\nconcurrently (bounded) and each is idempotent; per-item failures do not\nabort the batch — the response reports the outcome of every item in order."
      },
      "CompanyImportBatchResponse": {
        "properties": {
          "results": {
            "items": {
              "$ref": "#/components/schemas/CompanyImportBatchResult"
            },
            "type": "array",
            "title": "Results"
          },
          "imported": {
            "type": "integer",
            "title": "Imported",
            "description": "Count of items that imported successfully."
          },
          "failed": {
            "type": "integer",
            "title": "Failed",
            "description": "Count of items that failed."
          }
        },
        "type": "object",
        "required": [
          "results",
          "imported",
          "failed"
        ],
        "title": "CompanyImportBatchResponse"
      },
      "CompanyImportBatchResult": {
        "properties": {
          "index": {
            "type": "integer",
            "title": "Index",
            "description": "0-based position of the item in the request."
          },
          "sovosCompanyId": {
            "type": "string",
            "title": "Sovoscompanyid"
          },
          "status": {
            "type": "string",
            "enum": [
              "imported",
              "failed"
            ],
            "title": "Status"
          },
          "companyId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Companyid"
          },
          "peppolId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Peppolid"
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error"
          }
        },
        "type": "object",
        "required": [
          "index",
          "sovosCompanyId",
          "status"
        ],
        "title": "CompanyImportBatchResult"
      },
      "CompanyImportRequest": {
        "properties": {
          "siret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Siret",
            "description": "French SIRET (14 digits) — the primary portal input; SIREN, country and Peppol id are derived from it."
          },
          "siren": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Siren",
            "description": "French SIREN (9 digits) — alternative to `siret`."
          },
          "sovosOrganizationId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sovosorganizationid",
            "description": "Sovos organization (tenant). Defaults to the configured SOVOS_ORGANIZATION_ID when omitted."
          },
          "sovosCompanyId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sovoscompanyid",
            "description": "Existing Sovos company id to import; omit to provision from the SIRET instead."
          },
          "companyName": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Companyname",
            "description": "Company display name (resolved from the annuaire when omitted)."
          },
          "countryCode": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2,
                "minLength": 2
              },
              {
                "type": "null"
              }
            ],
            "title": "Countrycode",
            "description": "ISO 3166-1 alpha-2; implied FR from a SIRET/SIREN."
          },
          "mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mode",
            "description": "Sovos connection mode. Defaults to 'managed'.",
            "default": "managed"
          },
          "credentials": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Credentials",
            "description": "Optional {apiKey, apiSecret} for a self-managed (unmanaged) connection; omit for managed mode."
          }
        },
        "type": "object",
        "title": "CompanyImportRequest",
        "description": "Body for POST /v1/companies/import — the portability *migration* step.\n\nTwo entry points, one of which is required:\n\n* **SIRET only** (the portal case) — the taxpayer files a portability\n  request giving just its ``siret`` (or ``siren``). Flowie derives the SIREN,\n  country (FR) and Peppol id, resolves the legal name (and current PA) from\n  the PPF annuaire, then provisions the company on Sovos (using the request's\n  ``sovosOrganizationId`` or the configured ``SOVOS_ORGANIZATION_ID`` default),\n  or registers it locally as pending when no Sovos org is known.\n* **Existing Sovos company** — supply ``sovosOrganizationId`` +\n  ``sovosCompanyId`` to PULL an already-provisioned Sovos company instead of\n  provisioning a new one.",
        "examples": [
          {
            "siret": "92137626500018"
          },
          {
            "companyName": "HOZELOCK EXEL",
            "countryCode": "FR",
            "mode": "managed",
            "sovosCompanyId": "SOVOS-CMP-42",
            "sovosOrganizationId": "SOVOS-ORG-1"
          }
        ]
      },
      "CompanyListItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "organizationId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Organizationid"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "slug": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Slug"
          },
          "legalName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Legalname"
          },
          "type": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Association",
                  "Branch",
                  "Charity",
                  "Cooperative",
                  "EducationalInstitution",
                  "FamilyOffice",
                  "ForeignEntity",
                  "Franchise",
                  "Government",
                  "Headquarters",
                  "Healthcare",
                  "HoldingCompany",
                  "Individual",
                  "InvestmentFund",
                  "JointVenture",
                  "LimitedLiabilityCompany",
                  "Municipal",
                  "Nonprofit",
                  "Partnership",
                  "PrivateCompany",
                  "PublicCompany",
                  "SoleProprietorship",
                  "Subsidiary",
                  "Trust",
                  "Other",
                  "Unknown"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Type"
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country"
          },
          "vatNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatnumber"
          },
          "taxNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Taxnumber"
          },
          "registrationNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Registrationnumber"
          },
          "legalStatus": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Active",
                  "Bankrupt",
                  "Closed",
                  "Inactive",
                  "Merged",
                  "UnderInvestigation",
                  "Unknown"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Legalstatus"
          },
          "legalAddressId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Legaladdressid"
          },
          "isPublic": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ispublic"
          },
          "dataProviderType": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Bce",
                  "Dnb",
                  "Pappers",
                  "Whitepages"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Dataprovidertype"
          },
          "dataProviderSyncDate": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dataprovidersyncdate"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "updatedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedat"
          },
          "peppolId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Peppolid"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status"
          },
          "stats": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stats"
          }
        },
        "type": "object",
        "required": [
          "id"
        ],
        "title": "CompanyListItem",
        "description": "Lightweight company entry returned by GET /v1/companies — surfaces enough\nfields to render a list (name + identifiers + status) without forcing the\ncaller to fetch the full profile for every row."
      },
      "CompanyRegisterRequest": {
        "properties": {
          "sovosOrganizationId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sovosorganizationid",
            "description": "Genuine Sovos organization id. Required to provision a new Sovos customer configuration / managed connection."
          },
          "sovosProduct": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sovosproduct",
            "description": "Sovos product flow. Defaults to 'compliancenetwork'."
          },
          "erpSystemId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Erpsystemid",
            "description": "ERP system id label on the Sovos config."
          },
          "mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mode",
            "description": "Sovos connection mode. Defaults to 'managed'."
          }
        },
        "type": "object",
        "title": "CompanyRegisterRequest",
        "description": "Body for POST /v1/companies/{id}/register — deploy the org on Peppol.\n\nAll fields optional: if the org already has a Sovos customer config, the\nregister call re-syncs and activates it. To provision a NOT-yet-configured\norg, ``sovosOrganizationId`` is required (a genuine Sovos-issued org id;\nSovos rejects arbitrary values)."
      },
      "CompanyResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Organization ID (UUID)"
          },
          "organizationId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Organizationid",
            "description": "Canonical organization ID — usually equal to `id`"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "internalName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Internalname",
            "description": "Operator-only display name"
          },
          "slug": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Slug",
            "description": "URL-safe slug"
          },
          "legalName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Legalname"
          },
          "type": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Association",
                  "Branch",
                  "Charity",
                  "Cooperative",
                  "EducationalInstitution",
                  "FamilyOffice",
                  "ForeignEntity",
                  "Franchise",
                  "Government",
                  "Headquarters",
                  "Healthcare",
                  "HoldingCompany",
                  "Individual",
                  "InvestmentFund",
                  "JointVenture",
                  "LimitedLiabilityCompany",
                  "Municipal",
                  "Nonprofit",
                  "Partnership",
                  "PrivateCompany",
                  "PublicCompany",
                  "SoleProprietorship",
                  "Subsidiary",
                  "Trust",
                  "Other",
                  "Unknown"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Type",
            "description": "Legal form classification (e.g. PrivateCompany)"
          },
          "industry": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Industry"
          },
          "industryCodeLabel": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Industrycodelabel"
          },
          "dateEstablished": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dateestablished"
          },
          "registrationDate": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ],
            "title": "Registrationdate"
          },
          "websiteUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Websiteurl"
          },
          "missionStatement": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Missionstatement"
          },
          "visionStatement": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Visionstatement"
          },
          "sizeRange": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sizerange",
            "description": "Employee headcount range"
          },
          "annualRevenueRange": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Annualrevenuerange"
          },
          "capital": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Capital",
            "description": "Registered share capital"
          },
          "capitalCurrency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Capitalcurrency",
            "description": "ISO 4217 currency code"
          },
          "ownershipStructure": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ownershipstructure"
          },
          "socialMediaHandle": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Socialmediahandle"
          },
          "logoUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Logourl"
          },
          "country": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2
              },
              {
                "type": "null"
              }
            ],
            "title": "Country",
            "description": "ISO 3166-1 alpha-2"
          },
          "vatNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatnumber"
          },
          "taxNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Taxnumber"
          },
          "dunsNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dunsnumber",
            "description": "D-U-N-S 9-digit identifier"
          },
          "euid": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Euid",
            "description": "European Unique Identifier"
          },
          "registrationNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Registrationnumber",
            "description": "Preferred registration number (e.g. SIRET / SIREN / KvK)"
          },
          "additionalIdentifiers": {
            "anyOf": [
              {
                "items": {},
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Additionalidentifiers"
          },
          "legalForm": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Legalform",
            "description": "e.g. SAS, SARL, GmbH"
          },
          "legalStatus": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Active",
                  "Bankrupt",
                  "Closed",
                  "Inactive",
                  "Merged",
                  "UnderInvestigation",
                  "Unknown"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Legalstatus"
          },
          "legalStatusReason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Legalstatusreason"
          },
          "legalStatusEffectiveDate": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ],
            "title": "Legalstatuseffectivedate"
          },
          "legalAddressId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Legaladdressid",
            "description": "UUID of the legal address (also embedded as `address`)"
          },
          "address": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ],
            "description": "Resolved legal address"
          },
          "mergedWithOrganization": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mergedwithorganization",
            "description": "If this org was merged, the surviving org ID"
          },
          "isRecoverable": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isrecoverable"
          },
          "isPublic": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ispublic"
          },
          "dataProviderType": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Bce",
                  "Dnb",
                  "Pappers",
                  "Whitepages"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Dataprovidertype",
            "description": "Source registry that last enriched this record"
          },
          "dataProviderSyncDate": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dataprovidersyncdate"
          },
          "createdBy": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdby"
          },
          "updatedBy": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedby"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "updatedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedat"
          },
          "peppolId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Peppolid"
          },
          "capabilities": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Capabilities"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status",
            "description": "active, inactive, suspended"
          },
          "smpRegistered": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Smpregistered"
          },
          "smpRegisteredAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Smpregisteredat"
          },
          "compliance": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Compliance"
          },
          "enrichment": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Enrichment"
          },
          "settings": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Settings"
          },
          "stats": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stats"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          }
        },
        "type": "object",
        "required": [
          "id"
        ],
        "title": "CompanyResponse",
        "description": "Full company profile — mirrors org-v2 Organization plus Peppol-specific fields.",
        "examples": [
          {
            "address": {
              "city": "ARNAS",
              "country": "FR",
              "postalCode": "69400",
              "street": "891 ROUTE DES FRENES",
              "streetLine2": "Z.I.DE JOUX ARNAS NORD"
            },
            "country": "FR",
            "createdAt": "2025-11-10T15:21:03.581980Z",
            "dataProviderSyncDate": "2025-11-10T15:21:04.068319Z",
            "dataProviderType": "Whitepages",
            "id": "019a6e5b-3960-7000-ab88-153aed5a6240",
            "isPublic": false,
            "legalAddressId": "019a6e5b-3b4c-7000-a460-a09181acc257",
            "legalName": "HOZELOCK EXEL",
            "name": "HOZELOCK EXEL",
            "organizationId": "019a6e5b-3960-7000-ab88-153aed5a6240",
            "peppolId": "0009:02779658772",
            "registrationNumber": "77965877200024",
            "slug": "hozelock-exel",
            "smpRegistered": true,
            "status": "active",
            "taxNumber": "FR02779658772",
            "updatedAt": "2026-03-06T09:08:26.855434Z",
            "vatNumber": "FR02779658772"
          }
        ]
      },
      "CompanyUpdate": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "address": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ]
          },
          "capabilities": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Capabilities"
          },
          "settings": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Settings"
          },
          "compliance": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Compliance"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          }
        },
        "type": "object",
        "title": "CompanyUpdate"
      },
      "ComplianceReportRecord": {
        "properties": {
          "documentId": {
            "type": "string",
            "title": "Documentid"
          },
          "type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Type"
          },
          "number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Number"
          },
          "issueDate": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Issuedate"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status"
          },
          "reportedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reportedat"
          },
          "reportedTo": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reportedto"
          },
          "platformResponse": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Platformresponse"
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Error"
          }
        },
        "type": "object",
        "required": [
          "documentId"
        ],
        "title": "ComplianceReportRecord"
      },
      "ComplianceReportResponse": {
        "properties": {
          "records": {
            "items": {
              "$ref": "#/components/schemas/ComplianceReportRecord"
            },
            "type": "array",
            "title": "Records",
            "default": []
          }
        },
        "type": "object",
        "title": "ComplianceReportResponse"
      },
      "ComplianceStatusResponse": {
        "properties": {
          "companies": {
            "items": {
              "$ref": "#/components/schemas/CompanyComplianceItem"
            },
            "type": "array",
            "title": "Companies",
            "default": []
          }
        },
        "type": "object",
        "title": "ComplianceStatusResponse"
      },
      "DirectoryLineSearchRequest": {
        "properties": {
          "filters": {
            "additionalProperties": true,
            "type": "object",
            "title": "Filters"
          },
          "sorting": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sorting"
          },
          "fields": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fields"
          },
          "include": {
            "anyOf": [
              {
                "items": {
                  "type": "string",
                  "enum": [
                    "siren",
                    "siret",
                    "routingCode"
                  ]
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Include"
          },
          "limit": {
            "type": "integer",
            "maximum": 100.0,
            "minimum": 1.0,
            "title": "Limit",
            "default": 50
          },
          "ignore": {
            "type": "integer",
            "maximum": 10000.0,
            "minimum": 0.0,
            "title": "Ignore",
            "default": 0
          }
        },
        "type": "object",
        "title": "DirectoryLineSearchRequest",
        "description": "Request body for POST /v1/directory-line/search."
      },
      "DirectoryLineSearchResponse": {
        "properties": {
          "search": {
            "additionalProperties": true,
            "type": "object",
            "title": "Search"
          },
          "totalNumberOfResults": {
            "type": "integer",
            "title": "Totalnumberofresults"
          },
          "results": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array",
            "title": "Results"
          }
        },
        "type": "object",
        "required": [
          "search",
          "totalNumberOfResults",
          "results"
        ],
        "title": "DirectoryLineSearchResponse",
        "description": "Response body for POST /v1/directory-line/search."
      },
      "DirectoryLookupResponse": {
        "properties": {
          "peppolId": {
            "type": "string",
            "title": "Peppolid"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country"
          },
          "city": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "City"
          },
          "postalCode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Postalcode"
          },
          "vatNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatnumber"
          },
          "registeredSince": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Registeredsince"
          },
          "documentTypes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Documenttypes",
            "default": []
          },
          "accessPoint": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Accesspoint"
          },
          "capabilities": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Capabilities"
          },
          "enrichment": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Enrichment"
          },
          "smpStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Smpstatus"
          }
        },
        "type": "object",
        "required": [
          "peppolId"
        ],
        "title": "DirectoryLookupResponse"
      },
      "DirectorySearchResult": {
        "properties": {
          "peppolId": {
            "type": "string",
            "title": "Peppolid"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country"
          },
          "city": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "City"
          },
          "postalCode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Postalcode"
          },
          "vatNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatnumber"
          },
          "registeredSince": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Registeredsince"
          },
          "documentTypes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Documenttypes",
            "default": []
          },
          "accessPoint": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Accesspoint"
          }
        },
        "type": "object",
        "required": [
          "peppolId"
        ],
        "title": "DirectorySearchResult"
      },
      "DocumentBody": {
        "properties": {
          "number": {
            "type": "string",
            "maxLength": 100,
            "minLength": 1,
            "title": "Number"
          },
          "issueDate": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Issuedate",
            "description": "ISO 8601 date (YYYY-MM-DD) — required for invoices/credit-notes, optional for events"
          },
          "dueDate": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Duedate"
          },
          "currency": {
            "type": "string",
            "maxLength": 3,
            "minLength": 3,
            "pattern": "^[A-Z]{3}$",
            "title": "Currency",
            "description": "ISO 4217 currency code",
            "default": "EUR"
          },
          "buyerReference": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Buyerreference"
          },
          "orderReference": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Orderreference"
          },
          "billingReference": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Billingreference",
            "description": "Reference to the invoice this document amends (BT-25). Renders as the UBL `BillingReference/InvoiceDocumentReference/ID`. Required for credit-notes and debit-notes under the FR reform (BR-FR-CO-04/BR-FR-CO-05); ignored for plain invoices. Maps to the tx-docs `originalInvoiceId` field. Also accepted under its former name `precedingInvoiceReference`."
          },
          "billingReferenceDate": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Billingreferencedate",
            "description": "Issue date (YYYY-MM-DD) of the referenced invoice (BT-26). Renders as `BillingReference/InvoiceDocumentReference/IssueDate`. Maps to the tx-docs `originalInvoiceIssuedAt` field. Also accepted under its former name `precedingInvoiceIssueDate`."
          },
          "note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Note"
          },
          "seller": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PartyInfo"
              },
              {
                "type": "null"
              }
            ]
          },
          "buyer": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PartyInfo"
              },
              {
                "type": "null"
              }
            ]
          },
          "parties": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/PartyRef"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Parties",
            "description": "Explicit, role-tagged party list for multi-party documents and self-billing. When provided it OVERRIDES the default seller/buyer derivation; exactly one entry must be the `initiator` (the acting org). Omit for the common seller→buyer case."
          },
          "payment": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/PaymentInfo"
              },
              {
                "type": "null"
              }
            ]
          },
          "delivery": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Delivery",
            "description": "Delivery information (delivery date / `deliveryLocation` address). Only the deliver-to COUNTRY is rendered by the structured `format=json` pipeline today (BT-80, required by BR-IC-12 on intra-community supplies); it is read from `deliveryLocation.country`. On an intra-community supply (`vatCategory: \"K\"`) it defaults to the buyer's country when omitted. The rest of the delivery group is accepted but not yet rendered — carry it in the XML with `format=ubl-xml` if you need it."
          },
          "lines": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/InvoiceLine"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lines",
            "description": "Required for invoices/credit-notes, optional for events"
          },
          "allowances": {
            "anyOf": [
              {
                "items": {},
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Allowances",
            "description": "Document-level allowances/discounts, e.g. `[{\"amount\": 50.0, \"reason\": \"Loyalty discount\", \"vatRate\": 21.0}]`. ACCEPTED but NOT YET rendered by the structured `format=json` pipeline — use `format=ubl-xml` to carry them today."
          },
          "charges": {
            "anyOf": [
              {
                "items": {},
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Charges",
            "description": "Document-level charges (shipping, packaging…), e.g. `[{\"amount\": 25.0, \"reason\": \"Shipping\", \"vatRate\": 21.0}]`. ACCEPTED but NOT YET rendered by the structured `format=json` pipeline — use `format=ubl-xml` to carry them today."
          },
          "attachments": {
            "anyOf": [
              {
                "items": {},
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Attachments",
            "description": "Embedded supporting documents (base64), e.g. `[{\"filename\": \"timesheet.pdf\", \"contentType\": \"application/pdf\", \"content\": \"<base64>\"}]`. ACCEPTED but NOT YET attached by the structured `format=json` pipeline — POST the file via `format=auto`/`raw`, or embed it in `format=ubl-xml`."
          },
          "totals": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Totals",
            "description": "Pre-computed totals — `{\"netAmount\": …, \"vatAmount\": …, \"grossAmount\": …}` (the short keys `net`/`vat`/`gross` are also accepted). Omit and Flowie sums the lines; if provided, these override the computed amounts."
          },
          "templateId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Templateid",
            "description": "UUID of the transaction-document template to file this document under (your org's template for this document type). The template defines which `customFields` are accepted, their types and whether each is line- or document-level. Omit to use your org's default template for the type. List your templates via tx-docs `GET /v1/organizations/{org}/fields` (field definitions) / the templates API."
          },
          "customFields": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Customfields",
            "description": "Document-level custom field values, keyed by the field's name OR its definition UUID (names are resolved to UUIDs before submission). Attached to YOUR party on the document (the acting org / initiator). Values follow the field's type: a bare string for text/date fields, `{\"currency\": \"EUR\", \"amount\": 12.5}` for monetary fields, or an address object (`{street, street2, city, zipCode, country}`) for address fields. The fields must be declared on the document's `templateId`."
          }
        },
        "type": "object",
        "required": [
          "number"
        ],
        "title": "DocumentBody",
        "description": "Structured document body. Invoice-specific fields (issueDate, lines)\nare optional at the schema level so the same shape can carry events\nthat only need `number`. Invoice/credit-note pipelines re-validate\npresence of these fields before submitting to tx-docs."
      },
      "DocumentListItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Type"
          },
          "direction": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Direction"
          },
          "number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Number"
          },
          "issueDate": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Issuedate"
          },
          "dueDate": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Duedate"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Currency"
          },
          "grossAmount": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Grossamount"
          },
          "sender": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sender"
          },
          "receiver": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Receiver"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status"
          },
          "deliveryStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Deliverystatus"
          },
          "receivedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Receivedat"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          }
        },
        "type": "object",
        "required": [
          "id"
        ],
        "title": "DocumentListItem"
      },
      "DocumentResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Type",
            "description": "INVOICE, CREDIT_NOTE, DEBIT_NOTE, PURCHASE_ORDER"
          },
          "direction": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Direction",
            "description": "incoming or outgoing"
          },
          "number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Number"
          },
          "issueDate": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Issuedate"
          },
          "dueDate": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Duedate"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Currency"
          },
          "grossAmount": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Grossamount"
          },
          "netAmount": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Netamount"
          },
          "vatAmount": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatamount"
          },
          "sender": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sender"
          },
          "receiver": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Receiver"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status",
            "description": "Exact lifecycleStatus (org-specific, may be localized, e.g. 'draft', 'sent')."
          },
          "deliveryStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Deliverystatus",
            "description": "pending, delivered, failed, rejected"
          },
          "lifecycleStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lifecyclestatus"
          },
          "document": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DocumentBody"
              },
              {
                "type": "null"
              }
            ]
          },
          "xml": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Xml"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          },
          "receivedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Receivedat"
          },
          "sentAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sentat"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "updatedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedat"
          }
        },
        "type": "object",
        "required": [
          "id"
        ],
        "title": "DocumentResponse",
        "examples": [
          {
            "currency": "EUR",
            "deliveryStatus": "delivered",
            "direction": "outgoing",
            "grossAmount": 1815.0,
            "id": "doc_abc123",
            "issueDate": "2026-04-15",
            "netAmount": 1500.0,
            "number": "INV-2026-0042",
            "status": "sent",
            "type": "INVOICE",
            "vatAmount": 315.0
          }
        ]
      },
      "ErrorDetail": {
        "properties": {
          "field": {
            "type": "string",
            "title": "Field"
          },
          "rule": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Rule"
          },
          "message": {
            "type": "string",
            "title": "Message"
          }
        },
        "type": "object",
        "required": [
          "field",
          "message"
        ],
        "title": "ErrorDetail"
      },
      "ErrorResponse": {
        "properties": {
          "type": {
            "type": "string",
            "title": "Type"
          },
          "code": {
            "type": "string",
            "title": "Code"
          },
          "message": {
            "type": "string",
            "title": "Message"
          },
          "details": {
            "items": {
              "$ref": "#/components/schemas/ErrorDetail"
            },
            "type": "array",
            "title": "Details",
            "default": []
          },
          "requestId": {
            "type": "string",
            "title": "Requestid"
          },
          "docUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Docurl"
          }
        },
        "type": "object",
        "required": [
          "type",
          "code",
          "message",
          "requestId"
        ],
        "title": "ErrorResponse"
      },
      "EventResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "type": {
            "type": "string",
            "title": "Type"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat"
          },
          "data": {
            "additionalProperties": true,
            "type": "object",
            "title": "Data",
            "default": {}
          }
        },
        "type": "object",
        "required": [
          "id",
          "type",
          "createdAt"
        ],
        "title": "EventResponse"
      },
      "FileAttachment": {
        "properties": {
          "content": {
            "type": "string",
            "minLength": 1,
            "title": "Content",
            "description": "Base64-encoded file bytes. No data: prefix."
          },
          "contentType": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Contenttype",
            "description": "MIME type. Optional — server falls back to magic-byte sniff."
          },
          "filename": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Filename",
            "description": "Original filename, persisted on the file record."
          }
        },
        "type": "object",
        "required": [
          "content"
        ],
        "title": "FileAttachment",
        "description": "Raw file payload — used when sending a document whose body cannot be\nrepresented as structured JSON or UBL XML (e.g. a scanned PDF, an image,\na proprietary format). The content is base64-encoded; the server sniffs\nthe bytes to decide whether to route through the structured pipeline or\njust persist the file as-is via the document file API."
      },
      "Flow": {
        "properties": {
          "flowId": {
            "type": "string",
            "maxLength": 64,
            "title": "Flowid"
          },
          "submittedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Submittedat"
          },
          "name": {
            "type": "string",
            "maxLength": 255,
            "title": "Name"
          },
          "flowSyntax": {
            "type": "string",
            "enum": [
              "CII",
              "UBL",
              "Factur-X",
              "CDAR",
              "FRR"
            ],
            "title": "Flowsyntax"
          },
          "trackingId": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ],
            "title": "Trackingid"
          },
          "processingRule": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "B2B",
                  "B2BInt",
                  "B2C",
                  "B2G",
                  "B2GInt",
                  "OutOfScope",
                  "B2GOutOfScope",
                  "ArchiveOnly",
                  "NotApplicable",
                  "Undefined"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Processingrule"
          },
          "flowProfile": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Basic",
                  "CIUS",
                  "Extended-CTC-FR",
                  "Undefined"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Flowprofile"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Updatedat"
          },
          "flowType": {
            "type": "string",
            "title": "Flowtype"
          },
          "processingRuleSource": {
            "type": "string",
            "enum": [
              "Input",
              "Computed"
            ],
            "title": "Processingrulesource"
          },
          "flowDirection": {
            "type": "string",
            "enum": [
              "In",
              "Out"
            ],
            "title": "Flowdirection"
          },
          "acknowledgement": {
            "$ref": "#/components/schemas/FlowAcknowledgement"
          }
        },
        "type": "object",
        "required": [
          "flowId",
          "submittedAt",
          "name",
          "flowSyntax",
          "updatedAt",
          "flowType",
          "processingRuleSource",
          "flowDirection",
          "acknowledgement"
        ],
        "title": "Flow",
        "description": "CoreFlowInfo + FullFlowInfoExtension + FlowExtension."
      },
      "FlowAcknowledgement": {
        "additionalProperties": true,
        "type": "object"
      },
      "FullFlowInfo": {
        "properties": {
          "flowId": {
            "type": "string",
            "maxLength": 64,
            "title": "Flowid"
          },
          "submittedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Submittedat"
          },
          "name": {
            "type": "string",
            "maxLength": 255,
            "title": "Name"
          },
          "flowSyntax": {
            "type": "string",
            "enum": [
              "CII",
              "UBL",
              "Factur-X",
              "CDAR",
              "FRR"
            ],
            "title": "Flowsyntax"
          },
          "trackingId": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ],
            "title": "Trackingid"
          },
          "processingRule": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "B2B",
                  "B2BInt",
                  "B2C",
                  "B2G",
                  "B2GInt",
                  "OutOfScope",
                  "B2GOutOfScope",
                  "ArchiveOnly",
                  "NotApplicable",
                  "Undefined"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Processingrule"
          },
          "flowProfile": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Basic",
                  "CIUS",
                  "Extended-CTC-FR",
                  "Undefined"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Flowprofile"
          },
          "sha256": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sha256"
          }
        },
        "type": "object",
        "required": [
          "flowId",
          "submittedAt",
          "name",
          "flowSyntax"
        ],
        "title": "FullFlowInfo",
        "description": "FullFlowInfoExtension + FlowInfo."
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "HandoffCreateRequest": {
        "properties": {
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Scopes",
            "description": "Scopes pre-approved for the agent. Default = read-mostly send/receive set."
          },
          "label": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Label",
            "description": "Human-readable label — appears on the issued key, in audit logs, and in the dashboard.",
            "default": "AI agent handoff"
          },
          "ttl_seconds": {
            "type": "integer",
            "maximum": 3600.0,
            "minimum": 60.0,
            "title": "Ttl Seconds",
            "description": "How long the handoff token is valid before redemption (60–3600s).",
            "default": 600
          },
          "mode": {
            "type": "string",
            "enum": [
              "test",
              "live"
            ],
            "title": "Mode",
            "description": "test → flw_test_… key (default, safe). live → flw_live_… (only if your account is on a paid tier).",
            "default": "test"
          }
        },
        "type": "object",
        "title": "HandoffCreateRequest",
        "description": "Generate a single-use link to hand to an AI agent.\n\nThe authenticated user pre-approves a scope set bound to their org.\nThe agent receives the URL, calls ``POST /v1/oauth/handoff/exchange``\nwith the embedded token, and gets a scoped API key tied to the same\norganization — no consent UI required.\n\nScopes are filtered against the caller's own scopes: you cannot\npre-approve more than you have."
      },
      "HandoffCreateResponse": {
        "properties": {
          "handoff_token": {
            "type": "string",
            "title": "Handoff Token",
            "description": "Single-use token. Travels embedded in the URL."
          },
          "handoff_url": {
            "type": "string",
            "title": "Handoff Url",
            "description": "Full URL ready to paste into your LLM/agent prompt."
          },
          "expires_at": {
            "type": "string",
            "title": "Expires At",
            "description": "ISO 8601 expiry timestamp (UTC)."
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Scopes",
            "description": "The scopes the issued key will carry."
          },
          "organization_id": {
            "type": "string",
            "title": "Organization Id",
            "description": "The org the key will be bound to on redemption."
          }
        },
        "type": "object",
        "required": [
          "handoff_token",
          "handoff_url",
          "expires_at",
          "scopes",
          "organization_id"
        ],
        "title": "HandoffCreateResponse"
      },
      "HandoffExchangeRequest": {
        "properties": {
          "handoff_token": {
            "type": "string",
            "minLength": 10,
            "title": "Handoff Token",
            "description": "The token from the URL the user shared."
          }
        },
        "type": "object",
        "required": [
          "handoff_token"
        ],
        "title": "HandoffExchangeRequest",
        "description": "Step 2 — agent redeems the handoff token for an API key.\n\nThe token from the URL is the only credential needed. Single-use:\na second exchange returns 400."
      },
      "InvoiceLine": {
        "properties": {
          "description": {
            "type": "string",
            "maxLength": 500,
            "minLength": 1,
            "title": "Description"
          },
          "quantity": {
            "type": "number",
            "exclusiveMinimum": 0.0,
            "title": "Quantity"
          },
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Unit"
          },
          "unitPrice": {
            "type": "number",
            "minimum": 0.0,
            "title": "Unitprice"
          },
          "vatRate": {
            "type": "number",
            "maximum": 100.0,
            "minimum": 0.0,
            "title": "Vatrate",
            "description": "VAT rate as percentage (e.g. 20.0)"
          },
          "vatCategory": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatcategory"
          },
          "vatExemptionReason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatexemptionreason",
            "description": "Human-readable reason why this line carries no VAT (BT-120), e.g. \"Exoneration TVA, art. 262 ter I du CGI\". Required by EN 16931 (BR-E-10/BR-IC-10/BR-G-10/BR-O-10) whenever `vatCategory` is a zero-VAT category (E/Z/AE/K/G/O). Ignored for standard-rated lines."
          },
          "vatExemptionCode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatexemptioncode",
            "description": "VATEX code backing `vatExemptionReason` (BT-121), e.g. \"VATEX-EU-IC\" for an intra-community supply or \"VATEX-EU-AE\" for reverse charge. Optional: EN 16931 accepts the reason text alone."
          },
          "itemCode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Itemcode"
          },
          "period": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period"
          },
          "customFields": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Customfields",
            "description": "Line-level custom field values, keyed by the field's name OR its definition UUID. Names are resolved to UUIDs against the org's field definitions before submission. Values follow the field's type: a bare string for text/date fields, `{\"currency\": \"EUR\", \"amount\": 12.5}` for monetary fields, or an address object (`{street, street2, city, zipCode, country}`) for address fields. The fields must be declared on the document's template — see `document.templateId`."
          }
        },
        "type": "object",
        "required": [
          "description",
          "quantity",
          "unitPrice",
          "vatRate"
        ],
        "title": "InvoiceLine",
        "examples": [
          {
            "description": "Consulting services - April 2026",
            "quantity": 10.0,
            "unit": "HUR",
            "unitPrice": 150.0,
            "vatRate": 21.0
          }
        ]
      },
      "LifecycleHistoryEntry": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status"
          },
          "at": {
            "type": "string",
            "format": "date-time",
            "title": "At"
          },
          "setBy": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Setby"
          },
          "note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Note"
          },
          "reported": {
            "type": "boolean",
            "title": "Reported",
            "default": false
          },
          "reportedTo": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reportedto"
          },
          "reportedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reportedat"
          }
        },
        "type": "object",
        "required": [
          "status",
          "at"
        ],
        "title": "LifecycleHistoryEntry"
      },
      "LifecycleHistoryResponse": {
        "properties": {
          "documentId": {
            "type": "string",
            "title": "Documentid"
          },
          "currentStatus": {
            "type": "string",
            "title": "Currentstatus"
          },
          "currentStatusAt": {
            "type": "string",
            "format": "date-time",
            "title": "Currentstatusat"
          },
          "currentStatusReason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Currentstatusreason"
          },
          "compliance": {
            "additionalProperties": true,
            "type": "object",
            "title": "Compliance",
            "default": {}
          },
          "history": {
            "items": {
              "$ref": "#/components/schemas/LifecycleHistoryEntry"
            },
            "type": "array",
            "title": "History",
            "default": []
          },
          "allowedTransitions": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Allowedtransitions",
            "default": []
          }
        },
        "type": "object",
        "required": [
          "documentId",
          "currentStatus",
          "currentStatusAt"
        ],
        "title": "LifecycleHistoryResponse"
      },
      "LifecycleUpdateError": {
        "properties": {
          "status": {
            "type": "integer",
            "title": "Status",
            "description": "HTTP status this item would have returned on its own."
          },
          "detail": {
            "type": "string",
            "title": "Detail",
            "description": "Human-readable reason the transition was refused."
          }
        },
        "type": "object",
        "required": [
          "status",
          "detail"
        ],
        "title": "LifecycleUpdateError",
        "description": "Why one entry of a batch update failed.\n\nOnly ever set on `POST /documents/lifecycle/batch`, where individual items\nfail independently and the overall call still returns 200."
      },
      "LifecycleUpdateRequest": {
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "under_review",
              "approved",
              "sent",
              "rejected",
              "partially_paid",
              "paid",
              "disputed",
              "failed"
            ],
            "title": "Status",
            "description": "Target lifecycle status. `rejected` is **terminal** (in France it transmits 210 Refusée, cancelling the invoice for VAT and forcing a corrective) — when the issue may still be resolved, prioritize the reversible paths first: `disputed` to contest, or `disputed` + `reasonCode=\"suspended\"` to put the invoice on hold pending documents. `failed` transmits 213 Rejetée, the platform-side technical reject."
          },
          "reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason",
            "description": "Free-text explanation shown to the counterparty. Required alongside `reasonCode=OTH`; forwarded verbatim as MDT-114 on the French DGFiP leg."
          },
          "reasonCode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reasoncode",
            "description": "Coded reason for the transition — required for `rejected` and `disputed`. Use one of the 14 official Peppol status reason codes (OPStatusReason): `NON` (No issue), `REF` (References incorrect), `LEG` (Legal information incorrect), `REC` (Receiver unknown), `QUA` (Item quality insufficient), `DEL` (Delivery issues), `PRI` (Prices incorrect), `QTY` (Quantity incorrect), `ITM` (Items incorrect), `PAY` (Payment terms incorrect), `UNR` (Not recognized), `FIN` (Finance incorrect), `PPD` (Partially paid), `OTH` (Other). Full table: https://docs.get-flowie.com/reference/#reason-codes. France: an AFNOR XP Z12-012 motif code is forwarded verbatim as MDT-113 instead, and `suspended` (with `status=disputed`) transmits 208 Suspendue — so the field accepts free-form codes for those flows.",
            "examples": [
              "NON",
              "REF",
              "LEG",
              "REC",
              "QUA",
              "DEL",
              "PRI",
              "QTY",
              "ITM",
              "PAY",
              "UNR",
              "FIN",
              "PPD",
              "OTH",
              "suspended"
            ]
          },
          "note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Note"
          },
          "paymentDate": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Paymentdate"
          },
          "paymentReference": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Paymentreference"
          },
          "paymentAmount": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Paymentamount"
          },
          "paymentCurrency": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 3,
                "minLength": 3,
                "pattern": "^[A-Z]{3}$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Paymentcurrency"
          },
          "remainingAmount": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Remainingamount"
          }
        },
        "type": "object",
        "required": [
          "status"
        ],
        "title": "LifecycleUpdateRequest",
        "examples": [
          {
            "note": "Invoice verified against PO",
            "status": "approved"
          },
          {
            "paymentAmount": 1815.0,
            "paymentCurrency": "EUR",
            "paymentDate": "2026-04-15",
            "paymentReference": "PAY-2026-0042",
            "status": "paid"
          },
          {
            "reason": "Unit price on line 3 does not match the quote",
            "reasonCode": "PRI",
            "status": "rejected"
          }
        ]
      },
      "LifecycleUpdateResponse": {
        "properties": {
          "documentId": {
            "type": "string",
            "title": "Documentid"
          },
          "previousStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Previousstatus"
          },
          "currentStatus": {
            "type": "string",
            "title": "Currentstatus"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Updatedat"
          },
          "compliance": {
            "additionalProperties": true,
            "type": "object",
            "title": "Compliance",
            "default": {}
          },
          "allowedTransitions": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Allowedtransitions",
            "default": []
          },
          "error": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/LifecycleUpdateError"
              },
              {
                "type": "null"
              }
            ],
            "description": "Present only on a failed batch item. When set, `currentStatus` is `\"unknown\"` and no transition was applied — never treat the presence of a status field alone as success."
          }
        },
        "type": "object",
        "required": [
          "documentId",
          "currentStatus",
          "updatedAt"
        ],
        "title": "LifecycleUpdateResponse"
      },
      "PaginatedResponse_ApiKeyResponse_": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/ApiKeyResponse"
            },
            "type": "array",
            "title": "Data"
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore"
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cursor"
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore"
        ],
        "title": "PaginatedResponse[ApiKeyResponse]"
      },
      "PaginatedResponse_CompanyListItem_": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/CompanyListItem"
            },
            "type": "array",
            "title": "Data"
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore"
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cursor"
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore"
        ],
        "title": "PaginatedResponse[CompanyListItem]"
      },
      "PaginatedResponse_CompanyResponse_": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/CompanyResponse"
            },
            "type": "array",
            "title": "Data"
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore"
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cursor"
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore"
        ],
        "title": "PaginatedResponse[CompanyResponse]"
      },
      "PaginatedResponse_DirectorySearchResult_": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/DirectorySearchResult"
            },
            "type": "array",
            "title": "Data"
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore"
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cursor"
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore"
        ],
        "title": "PaginatedResponse[DirectorySearchResult]"
      },
      "PaginatedResponse_DocumentListItem_": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/DocumentListItem"
            },
            "type": "array",
            "title": "Data"
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore"
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cursor"
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore"
        ],
        "title": "PaginatedResponse[DocumentListItem]"
      },
      "PaginatedResponse_EventResponse_": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/EventResponse"
            },
            "type": "array",
            "title": "Data"
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore"
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cursor"
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore"
        ],
        "title": "PaginatedResponse[EventResponse]"
      },
      "PaginatedResponse_PartnerListItem_": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/PartnerListItem"
            },
            "type": "array",
            "title": "Data"
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore"
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cursor"
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore"
        ],
        "title": "PaginatedResponse[PartnerListItem]"
      },
      "PaginatedResponse_WebhookResponse_": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/WebhookResponse"
            },
            "type": "array",
            "title": "Data"
          },
          "hasMore": {
            "type": "boolean",
            "title": "Hasmore"
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cursor"
          }
        },
        "type": "object",
        "required": [
          "data",
          "hasMore"
        ],
        "title": "PaginatedResponse[WebhookResponse]"
      },
      "PartnerCreate": {
        "properties": {
          "peppolId": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}:.+$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Peppolid",
            "description": "Peppol participant ID (scheme:identifier)"
          },
          "vatNumber": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 20,
                "minLength": 4
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatnumber"
          },
          "role": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "supplier",
                  "buyer",
                  "both"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Role"
          },
          "contactName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contactname"
          },
          "contactEmail": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[^@]+@[^@]+\\.[^@]+$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contactemail"
          },
          "defaults": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Defaults"
          },
          "tags": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tags"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          }
        },
        "type": "object",
        "title": "PartnerCreate",
        "examples": [
          {
            "contactEmail": "jean@example.com",
            "contactName": "Jean Dupont",
            "peppolId": "0009:BE0123456789",
            "role": "supplier",
            "vatNumber": "BE0123456789"
          }
        ]
      },
      "PartnerListItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "peppolId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Peppolid"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country"
          },
          "role": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Role"
          },
          "peppolStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Peppolstatus"
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Tags",
            "default": []
          },
          "stats": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stats"
          }
        },
        "type": "object",
        "required": [
          "id"
        ],
        "title": "PartnerListItem"
      },
      "PartnerResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "peppolId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Peppolid"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "vatNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatnumber"
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country"
          },
          "role": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Role"
          },
          "contactName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contactname"
          },
          "contactEmail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contactemail"
          },
          "peppolStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Peppolstatus"
          },
          "defaults": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Defaults"
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Tags",
            "default": []
          },
          "enrichment": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Enrichment"
          },
          "stats": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stats"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "updatedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedat"
          }
        },
        "type": "object",
        "required": [
          "id"
        ],
        "title": "PartnerResponse",
        "examples": [
          {
            "country": "BE",
            "id": "part_abc123",
            "name": "Acme BVBA",
            "peppolId": "0009:BE0123456789",
            "peppolStatus": "active",
            "role": "supplier",
            "tags": [
              "preferred"
            ],
            "vatNumber": "BE0123456789"
          }
        ]
      },
      "PartnerUpdate": {
        "properties": {
          "peppolId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Peppolid"
          },
          "vatNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatnumber"
          },
          "role": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Role"
          },
          "contactName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contactname"
          },
          "contactEmail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contactemail"
          },
          "defaults": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Defaults"
          },
          "tags": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tags"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          }
        },
        "type": "object",
        "title": "PartnerUpdate"
      },
      "PartyInfo": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "vatNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatnumber"
          },
          "address": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ],
            "description": "Postal (billing) address. Mapped to the party's billingAddress on the e-invoice: `{street, street2 (from streetLine2), city, zipCode (from postalCode), country}`."
          },
          "shippingAddress": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ],
            "description": "Shipping address (same shape as `address`)."
          },
          "contact": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contact",
            "description": "Single contact `{name?, email?, phone?}`. Its `email` is added to the party's `contacts` list on the e-invoice. Use `contacts` to send several."
          },
          "contacts": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contacts",
            "description": "Contact email addresses carried on the party (free-text strings)."
          }
        },
        "type": "object",
        "title": "PartyInfo"
      },
      "PartyRef": {
        "properties": {
          "role": {
            "type": "string",
            "enum": [
              "seller",
              "buyer",
              "payer",
              "payee"
            ],
            "title": "Role"
          },
          "id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Id"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "vatNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatnumber"
          },
          "address": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ],
            "description": "Postal (billing) address. Mapped to billingAddress: `{street, street2 (from streetLine2), city, zipCode (from postalCode), country}`."
          },
          "shippingAddress": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ],
            "description": "Shipping address (same shape as `address`)."
          },
          "contact": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contact",
            "description": "Single contact `{name?, email?, phone?}`; its `email` is folded into `contacts`."
          },
          "contacts": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contacts",
            "description": "Contact email addresses carried on the party (free-text strings)."
          },
          "initiator": {
            "type": "boolean",
            "title": "Initiator",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "role"
        ],
        "title": "PartyRef",
        "description": "A document party with an explicit role — the building block for\nmulti-party documents (a payer/payee distinct from buyer/seller) and for\nlayouts where the issuer isn't the seller (self-billing).\n\nWhen a `document.parties` list is supplied it OVERRIDES the default\nseller/buyer derivation. Exactly one entry must set `initiator: true` — the\nparty acted by the calling organization (tx-docs requires the acting org to\nbe a party). Roles beyond seller/buyer/payer/payee are not modelled by the\nstructured pipeline today — use `format=ubl-xml` for those."
      },
      "PaymentInfo": {
        "properties": {
          "means": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Means"
          },
          "iban": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 34,
                "pattern": "^[A-Z]{2}\\d{2}[A-Z0-9]+$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Iban"
          },
          "bic": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 11,
                "pattern": "^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bic"
          },
          "reference": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reference"
          },
          "discountTerms": {
            "anyOf": [
              {
                "items": {},
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Discountterms"
          }
        },
        "type": "object",
        "title": "PaymentInfo"
      },
      "PlatformOnboardRequest": {
        "properties": {
          "vatNumber": {
            "type": "string",
            "title": "Vatnumber"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "address": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Address"
              },
              {
                "type": "null"
              }
            ]
          },
          "receiveDocuments": {
            "type": "boolean",
            "title": "Receivedocuments",
            "default": true
          },
          "autoVerify": {
            "type": "boolean",
            "title": "Autoverify",
            "default": false
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata"
          },
          "webhook": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Webhook"
          },
          "apiKey": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Apikey"
          }
        },
        "type": "object",
        "required": [
          "vatNumber"
        ],
        "title": "PlatformOnboardRequest"
      },
      "PlatformOnboardResponse": {
        "properties": {
          "company": {
            "$ref": "#/components/schemas/CompanyResponse"
          },
          "apiKey": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Apikey"
          },
          "webhook": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/WebhookResponse"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "type": "object",
        "required": [
          "company"
        ],
        "title": "PlatformOnboardResponse"
      },
      "PlatformSettingsUpdate": {
        "properties": {
          "branding": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Branding"
          },
          "defaults": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Defaults"
          },
          "customDomain": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Customdomain"
          }
        },
        "type": "object",
        "title": "PlatformSettingsUpdate"
      },
      "PlatformUsageResponse": {
        "properties": {
          "period": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period"
          },
          "total": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Total"
          },
          "byCompany": {
            "anyOf": [
              {
                "items": {},
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bycompany"
          }
        },
        "type": "object",
        "title": "PlatformUsageResponse"
      },
      "PortabilityMessageRequest": {
        "properties": {
          "messageType": {
            "type": "string",
            "enum": [
              "REQUEST",
              "ACK",
              "DECISION",
              "COMPLETION"
            ],
            "title": "Messagetype"
          },
          "state": {
            "type": "string",
            "enum": [
              "received",
              "acknowledged",
              "accepted",
              "rejected",
              "auto_accepted",
              "executing",
              "completed",
              "failed"
            ],
            "title": "State",
            "description": "Internal FSM state; mapped to the codified wire status."
          },
          "requestRef": {
            "type": "string",
            "maxLength": 64,
            "minLength": 1,
            "title": "Requestref",
            "description": "Stable portability request reference."
          },
          "directionRole": {
            "type": "string",
            "enum": [
              "GAINING_PA",
              "LOSING_PA"
            ],
            "title": "Directionrole",
            "default": "GAINING_PA"
          },
          "taxpayerSiren": {
            "type": "string",
            "pattern": "^[0-9]{9}$",
            "title": "Taxpayersiren",
            "description": "Taxpayer SIREN (9 digits)."
          },
          "taxpayerSiret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Taxpayersiret"
          },
          "taxpayerName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Taxpayername"
          },
          "gainingPaId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Gainingpaid"
          },
          "gainingPaName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Gainingpaname"
          },
          "losingPaId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Losingpaid"
          },
          "losingPaName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Losingpaname"
          },
          "effectiveDate": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Effectivedate",
            "description": "Date d'effet (ISO-8601)."
          },
          "transferredAddresses": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Transferredaddresses"
          },
          "mandateRef": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mandateref"
          },
          "mandateSignatory": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mandatesignatory"
          },
          "reasonCode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reasoncode",
            "description": "Required when state=rejected."
          },
          "reasonText": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reasontext"
          },
          "to": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "To",
            "description": "Counterparty PA channel address (only used if dispatch is enabled)."
          }
        },
        "type": "object",
        "required": [
          "messageType",
          "state",
          "requestRef",
          "taxpayerSiren"
        ],
        "title": "PortabilityMessageRequest",
        "description": "Build (and, behind the kill-switch, dispatch) an inter-PA message.",
        "examples": [
          {
            "directionRole": "GAINING_PA",
            "effectiveDate": "2026-10-01",
            "gainingPaId": "0040",
            "gainingPaName": "Flowie",
            "losingPaId": "0009:552081317",
            "losingPaName": "Autre PA",
            "mandateRef": "MANDATE-2026-42",
            "mandateSignatory": "Jane Dupont",
            "messageType": "REQUEST",
            "requestRef": "POR-2026-000123",
            "state": "received",
            "taxpayerName": "FLOWIE",
            "taxpayerSiren": "921376265",
            "taxpayerSiret": "92137626500018",
            "transferredAddresses": [
              "0009:92137626500018"
            ]
          }
        ]
      },
      "PortabilityMessageResponse": {
        "properties": {
          "subject": {
            "type": "string",
            "title": "Subject"
          },
          "messageType": {
            "type": "string",
            "title": "Messagetype"
          },
          "statusCode": {
            "type": "string",
            "title": "Statuscode"
          },
          "state": {
            "type": "string",
            "title": "State"
          },
          "filename": {
            "type": "string",
            "title": "Filename"
          },
          "csvHeader": {
            "type": "string",
            "title": "Csvheader"
          },
          "csvRow": {
            "type": "string",
            "title": "Csvrow"
          },
          "csv": {
            "type": "string",
            "title": "Csv"
          },
          "dispatched": {
            "type": "boolean",
            "title": "Dispatched"
          },
          "reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reason"
          },
          "note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Note"
          }
        },
        "type": "object",
        "required": [
          "subject",
          "messageType",
          "statusCode",
          "state",
          "filename",
          "csvHeader",
          "csvRow",
          "csv",
          "dispatched"
        ],
        "title": "PortabilityMessageResponse"
      },
      "PortabilityParseRequest": {
        "properties": {
          "subject": {
            "type": "string",
            "title": "Subject"
          },
          "csvRow": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Csvrow",
            "description": "One CSV data row (18 columns)."
          }
        },
        "type": "object",
        "required": [
          "subject"
        ],
        "title": "PortabilityParseRequest",
        "description": "Parse an inbound inter-PA message (normalised subject + one CSV row).",
        "examples": [
          {
            "csvRow": "POR-2026-000123;REQUEST;REQ;GAINING_PA;921376265;92137626500018;FLOWIE;0040;Flowie;0009:552081317;Autre PA;2026-10-01;0009:92137626500018;MANDATE-2026-42;Jane Dupont;2026-07-17T09:00:00+00:00;;",
            "subject": "[PORTABILITE][REQUEST][REQ][SIREN:921376265][REF:POR-2026-000123]"
          }
        ]
      },
      "PortabilityParseResponse": {
        "properties": {
          "messageType": {
            "type": "string",
            "title": "Messagetype"
          },
          "statusCode": {
            "type": "string",
            "title": "Statuscode"
          },
          "state": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "State",
            "description": "Internal FSM state resolved from the wire status code."
          },
          "siren": {
            "type": "string",
            "title": "Siren"
          },
          "requestRef": {
            "type": "string",
            "title": "Requestref"
          },
          "fields": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fields",
            "description": "Parsed CSV columns (present when csvRow was supplied)."
          }
        },
        "type": "object",
        "required": [
          "messageType",
          "statusCode",
          "siren",
          "requestRef"
        ],
        "title": "PortabilityParseResponse"
      },
      "RoutingCodeSearchRequest": {
        "properties": {
          "filters": {
            "additionalProperties": true,
            "type": "object",
            "title": "Filters"
          },
          "include": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Include"
          },
          "fields": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fields"
          },
          "sorting": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sorting"
          },
          "ignore": {
            "type": "integer",
            "maximum": 10000.0,
            "minimum": 0.0,
            "title": "Ignore",
            "default": 0
          },
          "limit": {
            "type": "integer",
            "maximum": 100.0,
            "minimum": 1.0,
            "title": "Limit",
            "default": 50
          }
        },
        "type": "object",
        "title": "RoutingCodeSearchRequest",
        "description": "Request body for POST /v1/routing-code/search."
      },
      "RoutingCodeSearchResponse": {
        "properties": {
          "search": {
            "additionalProperties": true,
            "type": "object",
            "title": "Search"
          },
          "totalNumberOfResults": {
            "type": "integer",
            "title": "Totalnumberofresults"
          },
          "results": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array",
            "title": "Results"
          }
        },
        "type": "object",
        "required": [
          "search",
          "totalNumberOfResults",
          "results"
        ],
        "title": "RoutingCodeSearchResponse",
        "description": "Response body for POST /v1/routing-code/search."
      },
      "SandboxBootstrapRequest": {
        "properties": {
          "label": {
            "type": "string",
            "maxLength": 64,
            "title": "Label",
            "description": "Free-form tag for the issued key — appears in the dashboard.",
            "default": "quickstart"
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "Optional contact email (we may follow up with usage tips)."
          },
          "keyType": {
            "type": "string",
            "pattern": "^(personal|platform|white_label)$",
            "title": "Keytype",
            "description": "Key type to mint. `personal` (default) is the regular tenant key every integrator gets. `platform` and `white_label` mint a key that satisfies the platform-key gate on `/v1/platform/*` so you can exercise multi-tenant ops in sandbox without involving sales.",
            "default": "personal"
          }
        },
        "type": "object",
        "title": "SandboxBootstrapRequest",
        "description": "Optional metadata for the bootstrapped sandbox tenant."
      },
      "SandboxBootstrapResponse": {
        "properties": {
          "organizationId": {
            "type": "string",
            "title": "Organizationid"
          },
          "apiKey": {
            "type": "string",
            "title": "Apikey"
          },
          "keyPrefix": {
            "type": "string",
            "title": "Keyprefix"
          },
          "keyType": {
            "type": "string",
            "title": "Keytype",
            "default": "personal"
          },
          "company": {
            "additionalProperties": true,
            "type": "object",
            "title": "Company"
          },
          "expiresAt": {
            "type": "string",
            "title": "Expiresat"
          },
          "nextSteps": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Nextsteps"
          },
          "docs": {
            "additionalProperties": true,
            "type": "object",
            "title": "Docs"
          }
        },
        "type": "object",
        "required": [
          "organizationId",
          "apiKey",
          "keyPrefix",
          "company",
          "expiresAt",
          "nextSteps",
          "docs"
        ],
        "title": "SandboxBootstrapResponse",
        "description": "The single response a brand-new integrator needs to start testing."
      },
      "SandboxClockAdvanceRequest": {
        "properties": {
          "companyId": {
            "type": "string",
            "title": "Companyid",
            "description": "Company whose virtual clock should be advanced."
          },
          "by": {
            "type": "string",
            "title": "By",
            "description": "How far to jump. Accepts compact units: `1h`, `3d`, `2w`, `1m`, `1y`.",
            "examples": [
              "60d",
              "12h",
              "1y"
            ]
          }
        },
        "type": "object",
        "required": [
          "companyId",
          "by"
        ],
        "title": "SandboxClockAdvanceRequest"
      },
      "SandboxClockResetRequest": {
        "properties": {
          "companyId": {
            "type": "string",
            "title": "Companyid"
          }
        },
        "type": "object",
        "required": [
          "companyId"
        ],
        "title": "SandboxClockResetRequest"
      },
      "SandboxClockResponse": {
        "properties": {
          "companyId": {
            "type": "string",
            "title": "Companyid"
          },
          "offsetSeconds": {
            "type": "integer",
            "title": "Offsetseconds"
          },
          "virtualNow": {
            "type": "string",
            "title": "Virtualnow"
          }
        },
        "type": "object",
        "required": [
          "companyId",
          "offsetSeconds",
          "virtualNow"
        ],
        "title": "SandboxClockResponse"
      },
      "SandboxIdempotencyFlushResponse": {
        "properties": {
          "organizationId": {
            "type": "string",
            "title": "Organizationid"
          },
          "deletedEntries": {
            "type": "integer",
            "title": "Deletedentries"
          }
        },
        "type": "object",
        "required": [
          "organizationId",
          "deletedEntries"
        ],
        "title": "SandboxIdempotencyFlushResponse"
      },
      "SandboxRateLimitExhaustRequest": {
        "properties": {
          "durationSeconds": {
            "type": "integer",
            "maximum": 3600.0,
            "minimum": 1.0,
            "title": "Durationseconds",
            "description": "How long the forced 429 should last. Max 1 hour.",
            "default": 60
          }
        },
        "type": "object",
        "title": "SandboxRateLimitExhaustRequest"
      },
      "SandboxRateLimitExhaustResponse": {
        "properties": {
          "organizationId": {
            "type": "string",
            "title": "Organizationid"
          },
          "durationSeconds": {
            "type": "integer",
            "title": "Durationseconds"
          },
          "expiresAt": {
            "type": "string",
            "title": "Expiresat"
          }
        },
        "type": "object",
        "required": [
          "organizationId",
          "durationSeconds",
          "expiresAt"
        ],
        "title": "SandboxRateLimitExhaustResponse"
      },
      "SandboxResetRequest": {
        "properties": {
          "confirm": {
            "type": "string",
            "const": "yes",
            "title": "Confirm",
            "description": "Type the literal string `yes` to acknowledge the wipe."
          },
          "scope": {
            "type": "string",
            "enum": [
              "all",
              "documents",
              "events",
              "idempotency"
            ],
            "title": "Scope",
            "description": "What to wipe. Defaults to everything.",
            "default": "all"
          }
        },
        "type": "object",
        "required": [
          "confirm"
        ],
        "title": "SandboxResetRequest",
        "description": "Body for POST /v1/sandbox/reset.\n\nRequires ``confirm: \"yes\"`` to prevent accidental wipes of an integrator's\nfixtures during day-to-day work. ``scope`` lets the caller narrow the\nblast radius to a single resource type."
      },
      "SandboxResetResponse": {
        "properties": {
          "deletedDocuments": {
            "type": "integer",
            "title": "Deleteddocuments",
            "default": 0
          },
          "deletedEvents": {
            "type": "integer",
            "title": "Deletedevents",
            "default": 0
          },
          "deletedIdempotencyEntries": {
            "type": "integer",
            "title": "Deletedidempotencyentries",
            "default": 0
          },
          "organizationId": {
            "type": "string",
            "title": "Organizationid"
          }
        },
        "type": "object",
        "required": [
          "organizationId"
        ],
        "title": "SandboxResetResponse"
      },
      "ScopeCatalogueResponse": {
        "properties": {
          "scopes": {
            "items": {
              "$ref": "#/components/schemas/ScopeDescriptor"
            },
            "type": "array",
            "title": "Scopes"
          }
        },
        "type": "object",
        "required": [
          "scopes"
        ],
        "title": "ScopeCatalogueResponse"
      },
      "ScopeDescriptor": {
        "properties": {
          "scope": {
            "type": "string",
            "title": "Scope"
          },
          "label": {
            "type": "string",
            "title": "Label"
          },
          "description": {
            "type": "string",
            "title": "Description"
          }
        },
        "type": "object",
        "required": [
          "scope",
          "label",
          "description"
        ],
        "title": "ScopeDescriptor"
      },
      "SearchFlowFilters": {
        "properties": {
          "updatedAfter": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedafter"
          },
          "updatedBefore": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedbefore"
          },
          "processingRule": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Processingrule"
          },
          "flowType": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flowtype"
          },
          "flowDirection": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flowdirection"
          },
          "trackingId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Trackingid"
          },
          "ackStatus": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Pending",
                  "Ok",
                  "Error"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Ackstatus"
          }
        },
        "type": "object",
        "title": "SearchFlowFilters",
        "description": "Filters for POST /v1/flows/search (SearchFlowFilters)."
      },
      "SearchFlowParams": {
        "properties": {
          "limit": {
            "type": "integer",
            "maximum": 100.0,
            "minimum": 1.0,
            "title": "Limit",
            "default": 25
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cursor"
          },
          "where": {
            "$ref": "#/components/schemas/SearchFlowFilters"
          }
        },
        "type": "object",
        "title": "SearchFlowParams",
        "description": "Request body for POST /v1/flows/search."
      },
      "SearchFlowResponse": {
        "properties": {
          "limit": {
            "type": "integer",
            "title": "Limit"
          },
          "nextCursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nextcursor"
          },
          "filters": {
            "additionalProperties": true,
            "type": "object",
            "title": "Filters"
          },
          "results": {
            "items": {
              "$ref": "#/components/schemas/Flow"
            },
            "type": "array",
            "title": "Results"
          }
        },
        "type": "object",
        "required": [
          "limit",
          "filters",
          "results"
        ],
        "title": "SearchFlowResponse",
        "description": "SearchFlowContent — response body for POST /v1/flows/search."
      },
      "SearchRequest": {
        "properties": {
          "query": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Query"
          },
          "filters": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Filters"
          },
          "sort": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sort"
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "default": 20
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cursor"
          }
        },
        "type": "object",
        "title": "SearchRequest"
      },
      "SendDocumentResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status"
          },
          "type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Type"
          },
          "number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Number"
          },
          "from": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "From"
          },
          "to": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "To"
          },
          "totals": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Totals"
          },
          "deliveryStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Deliverystatus"
          },
          "sentAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sentat"
          },
          "fileId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fileid"
          },
          "storedFormat": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Storedformat"
          }
        },
        "type": "object",
        "required": [
          "id"
        ],
        "title": "SendDocumentResponse"
      },
      "SirenSearchRequest": {
        "properties": {
          "filters": {
            "additionalProperties": true,
            "type": "object",
            "title": "Filters"
          },
          "sorting": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sorting"
          },
          "fields": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fields"
          },
          "limit": {
            "type": "integer",
            "maximum": 100.0,
            "minimum": 1.0,
            "title": "Limit",
            "default": 50
          },
          "ignore": {
            "type": "integer",
            "maximum": 10000.0,
            "minimum": 0.0,
            "title": "Ignore",
            "default": 0
          }
        },
        "type": "object",
        "title": "SirenSearchRequest",
        "description": "Request body for POST /v1/siren/search."
      },
      "SirenSearchResponse": {
        "properties": {
          "search": {
            "additionalProperties": true,
            "type": "object",
            "title": "Search"
          },
          "totalNumberOfResults": {
            "type": "integer",
            "title": "Totalnumberofresults"
          },
          "results": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array",
            "title": "Results"
          }
        },
        "type": "object",
        "required": [
          "search",
          "totalNumberOfResults",
          "results"
        ],
        "title": "SirenSearchResponse",
        "description": "Response body for POST /v1/siren/search."
      },
      "SiretSearchRequest": {
        "properties": {
          "filters": {
            "additionalProperties": true,
            "type": "object",
            "title": "Filters"
          },
          "sorting": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sorting"
          },
          "fields": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fields"
          },
          "include": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Include"
          },
          "limit": {
            "type": "integer",
            "maximum": 100.0,
            "minimum": 1.0,
            "title": "Limit",
            "default": 50
          },
          "ignore": {
            "type": "integer",
            "maximum": 10000.0,
            "minimum": 0.0,
            "title": "Ignore",
            "default": 0
          }
        },
        "type": "object",
        "title": "SiretSearchRequest",
        "description": "Request body for POST /v1/siret/search."
      },
      "SiretSearchResponse": {
        "properties": {
          "search": {
            "additionalProperties": true,
            "type": "object",
            "title": "Search"
          },
          "totalNumberOfResults": {
            "type": "integer",
            "title": "Totalnumberofresults"
          },
          "results": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array",
            "title": "Results"
          }
        },
        "type": "object",
        "required": [
          "search",
          "totalNumberOfResults",
          "results"
        ],
        "title": "SiretSearchResponse",
        "description": "Response body for POST /v1/siret/search."
      },
      "StatsResponse": {
        "properties": {
          "period": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period"
          },
          "quota": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Quota"
          },
          "rateLimit": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ratelimit"
          },
          "documents": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Documents"
          },
          "byType": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bytype"
          },
          "byCountry": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bycountry"
          },
          "partners": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Partners"
          }
        },
        "type": "object",
        "title": "StatsResponse"
      },
      "StructuredDocumentResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Type"
          },
          "direction": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Direction"
          },
          "number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Number"
          },
          "issueDate": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Issuedate"
          },
          "dueDate": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Duedate"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Currency"
          },
          "grossAmount": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Grossamount"
          },
          "netAmount": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Netamount"
          },
          "vatAmount": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vatamount"
          },
          "lifecycleStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lifecyclestatus"
          },
          "deliveryStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Deliverystatus"
          },
          "senderPeppolId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Senderpeppolid"
          },
          "senderName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sendername"
          },
          "senderVatNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sendervatnumber"
          },
          "receiverPeppolId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Receiverpeppolid"
          },
          "receiverName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Receivername"
          },
          "receiverVatNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Receivervatnumber"
          },
          "buyerReference": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Buyerreference"
          },
          "orderReference": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Orderreference"
          },
          "paymentIban": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Paymentiban"
          },
          "paymentReference": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Paymentreference"
          },
          "note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Note"
          },
          "receivedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Receivedat"
          },
          "sentAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sentat"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "updatedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedat"
          }
        },
        "type": "object",
        "required": [
          "id"
        ],
        "title": "StructuredDocumentResponse",
        "description": "Flat agent-friendly version with all primitives."
      },
      "TokenRequest": {
        "properties": {
          "grant_type": {
            "type": "string",
            "const": "authorization_code",
            "title": "Grant Type"
          },
          "code": {
            "type": "string",
            "minLength": 10,
            "title": "Code",
            "description": "The one-time code returned on consent."
          },
          "code_verifier": {
            "type": "string",
            "maxLength": 128,
            "minLength": 43,
            "title": "Code Verifier",
            "description": "The original PKCE verifier (the agent's secret)."
          }
        },
        "type": "object",
        "required": [
          "grant_type",
          "code",
          "code_verifier"
        ],
        "title": "TokenRequest",
        "description": "Step 4 — agent exchanges the auth code for an API key.\n\nImplements RFC 7636 PKCE: server hashes ``code_verifier`` with SHA-256\nand compares to the original ``code_challenge``."
      },
      "TokenResponse": {
        "properties": {
          "access_token": {
            "type": "string",
            "title": "Access Token",
            "description": "The issued API key. Format: flw_test_…"
          },
          "token_type": {
            "type": "string",
            "const": "Bearer",
            "title": "Token Type",
            "default": "Bearer"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Scopes"
          },
          "expires_in": {
            "type": "integer",
            "title": "Expires In",
            "description": "Seconds until the issued key expires."
          },
          "company_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Company Id",
            "description": "Sandbox company tied to the key."
          },
          "organization_id": {
            "type": "string",
            "title": "Organization Id",
            "description": "Sandbox org the key belongs to."
          }
        },
        "type": "object",
        "required": [
          "access_token",
          "scopes",
          "expires_in",
          "organization_id"
        ],
        "title": "TokenResponse"
      },
      "ValidateRequest": {
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "invoice",
              "credit-note",
              "debit-note",
              "purchase-order",
              "purchase-request",
              "sales-order",
              "quote",
              "event"
            ],
            "title": "Type"
          },
          "format": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "json",
                  "ubl-xml",
                  "cii-xml"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Format"
          },
          "from": {
            "type": "string",
            "title": "From"
          },
          "to": {
            "type": "string",
            "title": "To"
          },
          "document": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DocumentBody"
              },
              {
                "type": "null"
              }
            ]
          },
          "xml": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Xml"
          }
        },
        "type": "object",
        "required": [
          "type",
          "from",
          "to"
        ],
        "title": "ValidateRequest"
      },
      "ValidateResponse": {
        "properties": {
          "valid": {
            "type": "boolean",
            "title": "Valid"
          },
          "errors": {
            "items": {
              "$ref": "#/components/schemas/ErrorDetail"
            },
            "type": "array",
            "title": "Errors",
            "default": []
          },
          "warnings": {
            "items": {
              "$ref": "#/components/schemas/ErrorDetail"
            },
            "type": "array",
            "title": "Warnings",
            "default": []
          },
          "preview": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Preview"
          }
        },
        "type": "object",
        "required": [
          "valid"
        ],
        "title": "ValidateResponse"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "VerifyRequest": {
        "properties": {
          "peppolId": {
            "type": "string",
            "title": "Peppolid"
          },
          "documentType": {
            "type": "string",
            "title": "Documenttype"
          }
        },
        "type": "object",
        "required": [
          "peppolId",
          "documentType"
        ],
        "title": "VerifyRequest"
      },
      "VerifyResponse": {
        "properties": {
          "peppolId": {
            "type": "string",
            "title": "Peppolid"
          },
          "exists": {
            "type": "boolean",
            "title": "Exists"
          },
          "canReceive": {
            "type": "boolean",
            "title": "Canreceive"
          },
          "recipientName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Recipientname"
          },
          "documentType": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Documenttype"
          },
          "accessPoint": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Accesspoint"
          }
        },
        "type": "object",
        "required": [
          "peppolId",
          "exists",
          "canReceive"
        ],
        "title": "VerifyResponse"
      },
      "WebhookCreate": {
        "properties": {
          "url": {
            "type": "string",
            "pattern": "^https?://",
            "title": "Url",
            "description": "HTTPS webhook endpoint URL"
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "minItems": 1,
            "title": "Events",
            "description": "Event types to subscribe to: document.received, document.updated, document.sent, document.delivered, document.failed, lifecycle.updated, *"
          },
          "secret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Secret"
          },
          "companyId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Companyid"
          }
        },
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "title": "WebhookCreate",
        "examples": [
          {
            "events": [
              "document.received",
              "document.delivered"
            ],
            "secret": "whsec_abc123",
            "url": "https://example.com/webhooks/peppol"
          }
        ]
      },
      "WebhookMetadata": {
        "properties": {
          "flowType": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flowtype"
          },
          "flowDirection": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flowdirection"
          },
          "processingRule": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Processingrule"
          },
          "ackStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ackstatus"
          }
        },
        "type": "object",
        "title": "WebhookMetadata",
        "description": "WebhookMetadata — subscription filters.\n\nXP Z12-013 v1.3.0 removed every required metadata field — an empty\n``metadata`` object subscribes to all flow events. All fields are optional."
      },
      "WebhookParams": {
        "properties": {
          "callbackUrl": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Callbackurl"
          },
          "flowTypes": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flowtypes"
          },
          "flowDirection": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flowdirection"
          },
          "ackStatus": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ackstatus"
          },
          "callback": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CallbackParams"
              },
              {
                "type": "null"
              }
            ]
          },
          "metadata": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/WebhookMetadata"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "type": "object",
        "title": "WebhookParams",
        "description": "Request body for POST /v1/webhooks.\n\nThe AFNOR XP Z12-013 v1.3.0 swagger (`WebhookParams`) is the source of\ntruth: a flat body ``{callbackUrl, flowTypes[], flowDirection, ackStatus}``.\nFor backward compatibility this model ALSO accepts the legacy nested shape\n``{callback: {url, …}, metadata: {flowType, flowDirection, ackStatus}}`` so\nexisting consumers keep working. Read normalized values via the\n``resolved_*`` properties. At least one URL source is required."
      },
      "WebhookPatchPayload": {
        "properties": {
          "headers": {
            "anyOf": [
              {
                "items": {
                  "additionalProperties": true,
                  "type": "object"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Headers"
          },
          "authentication": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Authentication"
          },
          "signature": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Signature"
          }
        },
        "type": "object",
        "title": "WebhookPatchPayload",
        "description": "Request body for PATCH /v1/webhooks/{webhookUid} (technical-only update)."
      },
      "WebhookResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "url": {
            "type": "string",
            "title": "Url"
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Events",
            "default": []
          },
          "status": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "active",
                  "paused",
                  "disabled"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Status"
          },
          "companyId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Companyid"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "lastDeliveredAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lastdeliveredat"
          },
          "failureCount": {
            "type": "integer",
            "title": "Failurecount",
            "default": 0
          }
        },
        "type": "object",
        "required": [
          "id",
          "url"
        ],
        "title": "WebhookResponse",
        "examples": [
          {
            "events": [
              "document.received",
              "document.delivered"
            ],
            "failureCount": 0,
            "id": "wh_abc123",
            "status": "active",
            "url": "https://example.com/webhooks/peppol"
          }
        ]
      },
      "WebhookUpdate": {
        "properties": {
          "url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Url"
          },
          "events": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Events"
          },
          "rotateSecret": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Rotatesecret"
          }
        },
        "type": "object",
        "title": "WebhookUpdate"
      }
    }
  },
  "servers": [
    {
      "url": "https://back.p2p-flowie.com/exchange",
      "description": "Production"
    },
    {
      "url": "https://back.flowie.ink/exchange",
      "description": "Sandbox"
    }
  ],
  "externalDocs": {
    "url": "https://docs.get-flowie.com",
    "description": "Full developer documentation (HTML)"
  }
}