EUFactura
← Back to EUFactura

API for developers

EUFactura's public REST API (Scale plan) lets your own tools — a CRM, an e-commerce store, a custom script — create customers, draft and issue invoices and quotes, record payments, and get notified of key events via webhooks. Every endpoint wraps the exact same logic the EUFactura app itself uses, so nothing behaves differently through the API than it does in the UI.

Full reference

The complete API is described as an OpenAPI 3.1 specification — import it directly into Postman, Insomnia, or any OpenAPI-aware tool.

Authentication

Create a key from your organization's Settings → Developers page (owner/admin only). Each key is scoped to one organization and carries a role — member (read + write) or accountant (read-only). The full secret is shown once at creation; store it securely.

curl https://app.eufactura.eu/api/v1/customers?companyId=<company-id> \
  -H "Authorization: Bearer eufk_..."

Creating a customer and issuing an invoice

curl -X POST https://app.eufactura.eu/api/v1/customers \
  -H "Authorization: Bearer eufk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "companyId": "<company-id>",
    "type": "business",
    "legalName": "Acme GmbH",
    "countryCode": "DE"
  }'

curl -X POST https://app.eufactura.eu/api/v1/invoices \
  -H "Authorization: Bearer eufk_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: <a UUID you generate>" \
  -d '{
    "companyId": "<company-id>",
    "customerId": "<customer-id>",
    "currency": "EUR",
    "issueDate": "2026-01-01",
    "lines": [{ "description": "Consulting", "quantity": "1", "unitPriceNet": "500" }]
  }'

curl -X POST https://app.eufactura.eu/api/v1/invoices/<invoice-id>/issue \
  -H "Authorization: Bearer eufk_..."

Invoices are always created as drafts and issued as a separate, explicit step — issuing allocates the legal invoice number and makes the invoice immutable, matching how the app itself works.

Idempotency

Send an Idempotency-Key header (any string you generate, typically a UUID) on a mutating request. Retrying the same request with the same key returns the original response instead of performing the action a second time — safe against network retries and double-clicks.

Rate limits

Requests are limited per API key. A response over the limit returns 429 with a Retry-After-equivalent retryAfter field in the error body.

Errors

Every error comes back as {"error": {"code": "...", "message": "..."}}. A resource id belonging to a different organization always returns 404, never 403 — EUFactura never confirms that a resource exists before confirming you can access it.

Webhooks

Register an endpoint URL and choose which events to receive from Settings → Developers: invoice.issued, invoice.payment_recorded, quote.converted, and credit_note.issued. Each delivery is a signed HTTPS POST:

POST <your endpoint>
Content-Type: application/json
X-EUFactura-Signature: t=1700000000,v1=<hex-encoded HMAC-SHA256>

{"id": "...", "type": "invoice.issued", "data": { ... }}

Verify it by computing an HMAC-SHA256 of the timestamp, a literal dot, and the raw request body using your endpoint's secret, and comparing the result to the v1 value — the same t=...,v1=... shape Stripe itself uses for webhooks, so any Stripe webhook-verification code you already have is a good starting point. Deliveries are retried with backoff on failure (up to five attempts over about 12 hours); your endpoint should be idempotent on the payload's id.

Questions

Reach us at hello@eufactura.eu.