HTTP Reference — Generation API
The generation API (apps/api) is a stateless HTTP service hosted on the same VPS as the other Kortilabs apps. It exposes generation, validation and parsing operations for electronic invoices.
Base URL: https://api.facturation.kortilabs.com
Authentication
All generation routes require an Authorization: Bearer <PORTAL_HMAC_SECRET> header. API keys are managed from the OPERAT portal (/api/portal).
POST /api/v1/generate
Generates a Factur-X file (PDF/A-3 + EN 16931 CII XML).
Request body
{ "invoice": { "number": "INV-2026-0001", "typeCode": "380", "issueDate": "2026-06-01", "currency": "EUR", "seller": { "name": "ACME SAS", "siret": "12345678900012", "vatNumber": "FR12345678900", "address": { "street": "1 rue de la Paix", "city": "Paris", "postalCode": "75001", "country": "FR" } }, "buyer": { "name": "Client SAS", "siret": "98765432100019", "address": { "street": "5 avenue des Champs", "city": "Lyon", "postalCode": "69001", "country": "FR" } }, "lines": [ { "id": "1", "description": "Consulting services", "quantity": 2, "unitCode": "HUR", "unitPrice": 150, "vatRate": 20 } ], "paymentTerms": "Payment within 30 days" }}Response 200
{ "xml": "<base64>…</base64>", "pdf": "<base64>…</base64>", "validation": { "valid": true, "errors": [], "warnings": [] }}Error codes
| Code | Cause |
|---|---|
| 422 | Invalid invoice — validation.errors lists the failing BR-* rules |
| 400 | Malformed JSON |
| 401 | Missing or invalid API key |
POST /api/v1/validate
Validates an invoice against EN 16931 rules and French BR-FR-* rules without generating any file.
Request body
Same structure as /generate, invoice field only.
Response 200
{ "valid": false, "errors": [ { "rule": "BR-01", "message": "Invoice number is required", "path": "invoice.number" } ], "warnings": [ { "rule": "BR-FR-09", "message": "Seller SIREN recommended for French invoices", "path": "invoice.seller.siret" } ]}POST /api/v1/parse
Parses a Factur-X file (CII XML or UBL) and returns the normalised JSON structure.
Request body
{ "xml": "<base64-encoded XML file>" }Response 200
{ "format": "CII", "invoice": { "number": "INV-2026-0001", "…": "…" }, "validation": { "valid": true, "errors": [], "warnings": [] }}The format field is either "CII" (CrossIndustryInvoice — Factur-X) or "UBL" (Universal Business Language).
POST /check-xml
Validates the syntactic and structural conformity of an XML fragment without HMAC authentication. Useful for testing and PrestaShop integration.
Request body
{ "xml": "<raw XML content>" }Response 200
{ "valid": true, "format": "CII", "errors": [], "warnings": []}Webhooks — HMAC verification
The SDK exposes verifyWebhook to verify the signature of incoming webhooks (LemonSqueezy, PA, etc.).
import { verifyWebhook } from '@facturation/sdk';
// In your Next.js / Hono handlerconst isValid = verifyWebhook({ payload: rawBody, // Buffer or string of the raw body signature: req.headers['x-signature'], secret: process.env.LEMONSQUEEZY_WEBHOOK_SECRET,});
if (!isValid) return new Response('Unauthorized', { status: 401 });Verification uses crypto.timingSafeEqual to prevent timing attacks.
LemonSqueezy events handled
| Event | Action |
|---|---|
order_created | Upgrades user plan (SITE or MULTI) |
subscription_cancelled | Downgrades to FREE at end of period |
subscription_expired | Immediate downgrade to FREE |
Limits and quotas
| Limit | Value |
|---|---|
| Max request body size | 10 MB |
| Rate limiting | 100 req/min per IP |
| Batch invoices | Not available in v1 — 1 invoice per call |