Beta-HinweisBeta-Phase: Wir verfeinern noch einige Details. AGB und Datenschutz können in den kommenden Wochen aktualisiert werden.Mehr erfahren
e-Rechnung·Inbox

Public REST API v1

API-Dokumentation

Read-only mandantengebundene REST-API für e-Rechnung-Daten. Stabile URL, kursorbasierte Paginierung, signierte Webhooks.

Quickstart

Erzeugen Sie einen API-Schlüssel in den Workspace-Einstellungen und rufen Sie danach jeden Endpunkt mit Authorization-Header auf.

curl
# 1. Issue an API key in workspace settings → API keys.
# 2. Export it locally so curl can read it:
export ERI_API_KEY='eri_live_…'

# 3. List the 10 most recent invoices:
curl -s 'https://e-rechnung-inbox.de/api/public/v1/invoices?limit=10' \
  -H "Authorization: Bearer $ERI_API_KEY"
Node 18+ (fetch)
// Node 18+ (built-in fetch). No SDK required.
const res = await fetch(
  'https://e-rechnung-inbox.de/api/public/v1/invoices?limit=10',
  { headers: { Authorization: `Bearer ${process.env.ERI_API_KEY}` } },
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const { data, next_cursor } = await res.json();
console.log(data.length, 'invoices,', next_cursor ? 'more available' : 'end of list');

Alle Endpunkte sind read-only und mandantengebunden. Das Beispiel nutzt /invoices; dasselbe Muster funktioniert für /invoices/{id} und /suppliers.

Authentifizierung

Jede Anfrage an /api/public/v1/* benötigt einen API-Schlüssel — entweder im Authorization-Bearer-Header oder im X-API-Key-Header. Beide Varianten sind gleichwertig.

  • Authorization: Bearer eri_live_…
  • X-API-Key: eri_live_…

Schlüssel werden in den Workspace-Einstellungen unter "API-Schlüssel" erzeugt. Sie sind mandantengebunden — ein Steuerberater mit Zugriff auf mehrere Mandanten erzeugt pro Mandant einen Schlüssel.

Klartext-Schlüssel werden ausschließlich einmalig bei der Erstellung angezeigt. Bewahren Sie sie in einem Secrets-Store auf.

Endpunkte

Vollständige OpenAPI-3.1-Spezifikation: /api/public/v1/openapi.json.

GET/api/public/v1/invoicesinvoices

List invoices

Returns mandant-scoped invoices in receipt order (newest first). Cursor-paginated.

ParamInTypeNotes
cursorquerystringOpaque cursor from a previous response's `next_cursor`.
limitqueryinteger
statusqueryvalid | invalid | pdf_only
workflow_statusquerynew | reviewed | approved | paused | rejected | in_progress | exported | paid
supplier_idquerystring<uuid>
fromquerystring<date-time>
toquerystring<date-time>
has_iban_changequerybooleanFilter to invoices with a flagged IBAN change.

200OK

POST/api/public/v1/invoicesinvoices

Upload an invoice

Accepts a PDF/XML invoice file for asynchronous processing. Requires an API key with write scope, an `Idempotency-Key` header, and that public API write endpoints are enabled for the workspace/environment. CSV+ZIP export remains the supported fallback for downstream accounting.

ParamInTypeNotes
Idempotency-Key*headerstring

200OK

GET/api/public/v1/invoices/{id}invoices

Get a single invoice

ParamInTypeNotes
id*pathstring<uuid>
includequerystringComma-separated extras. `pdf_url` adds a 5-minute signed PDF URL.

200OK

PATCH/api/public/v1/invoices/{id}invoices

Update invoice workflow status

Narrow write endpoint for workflow_status changes only. Requires an API key with `write` scope and an `Idempotency-Key` header; all writes are mandant-scoped and audit-stamped.

ParamInTypeNotes
id*pathstring<uuid>
Idempotency-Key*headerstring

200Updated invoice.

GET/api/public/v1/supplierssuppliers

List suppliers

Returns mandant-scoped suppliers in name-ascending order. Cursor-paginated.

ParamInTypeNotes
cursorquerystring
limitqueryinteger
has_open_invoicesqueryboolean
vat_idquerystring

200OK

Code-Beispiele

Minimale Aufrufe zum Listen von Rechnungen:

Python
import os, requests
res = requests.get(
    "https://e-rechnung-inbox.de/api/public/v1/invoices",
    params={"limit": 10},
    headers={"Authorization": f"Bearer {os.environ['ERI_API_KEY']}"},
    timeout=10,
)
res.raise_for_status()
print(res.json()["data"])

Hosted MCP

Use the Public API key with Claude Desktop, Cursor, or Smithery via the hosted MCP endpoint. How to connect.

Webhooks

Erstellen Sie eine Subscription über die Workspace-Einstellungen. Wir senden eine signierte JSON-Payload per HTTPS POST. Unterstützte Event-Typen:

  • invoice.created
  • invoice.validated
  • invoice.flagged
  • invoice.workflow_status_changed
  • invoice.exported
  • supplier.created
  • supplier.iban_changed

Payload-Beispiele

Jedes Event nutzt denselben Envelope: id, type, created_at und data. Die Felder in data hängen vom Event ab; sensible Bankdaten werden nur minimiert weitergegeben.

invoice.created
{
  "id": "evt_01HV0CK7M5W9XGZN2Y9EGZ7T9R",
  "type": "invoice.created",
  "created_at": "2026-05-08T11:42:18.317Z",
  "data": {
    "invoice_id": "f3a3c5e0-3d3a-4f6e-9e9c-2d2dabec3d31",
    "invoice_number": "RE-2026-0142",
    "supplier": { "id": "8a2…", "name": "ACME GmbH" },
    "gross_total": 1428.0,
    "currency": "EUR"
  }
}
supplier.iban_changed
{
  "id": "evt_01HV0CK7M5W9XGZN2Y9EGZ7T9S",
  "type": "supplier.iban_changed",
  "created_at": "2026-05-08T11:42:18.317Z",
  "data": {
    "supplier_id": "8a2…",
    "supplier_name": "ACME GmbH",
    "previous_iban_last4": "0145",
    "new_iban_last4": "9921",
    "first_seen_in_invoice_id": "f3a3c5e0-3d3a-4f6e-9e9c-2d2dabec3d31"
  }
}

Signatur prüfen

Verifizierung der Signatur (Header X-ERI-Signature im Format t=UNIX_SECONDS,v1=HMAC_HEX):

JavaScript / Node
import crypto from 'node:crypto';

export function verifyEriWebhook(payload, signatureHeader, signingSecret) {
  // signatureHeader format: "t=<unix>,v1=<hex>"
  const parts = Object.fromEntries(
    signatureHeader.split(',').map((p) => p.split('=')),
  );
  const t = Number(parts.t);
  if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const expected = crypto.createHmac('sha256', signingSecret)
    .update(`${t}.${payload}`)
    .digest('hex');
  const actual = parts.v1 ?? '';
  return actual.length === expected.length && crypto.timingSafeEqual(
    Buffer.from(expected, 'utf8'),
    Buffer.from(actual, 'utf8'),
  );
}
Python
import hashlib, hmac, time

def verify_eri_webhook(payload: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t = int(parts.get("t", "0"))
    if abs(int(time.time()) - t) > 300:
        return False
    signed = f"{t}.{payload.decode('utf-8')}"
    expected = hmac.new(secret.encode("utf-8"), signed.encode("utf-8"),
                       hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

Retries und Auto-Disable

Bei Fehlschlägen wird der Backoff 1 min, 5 min, 30 min, 2 h, 12 h verwendet — maximal 5 Versuche. Nach 5 Fehlern in Folge wird die Subscription automatisch deaktiviert.

  • Fehlgeschlagene Zustellungen werden mit exponentiellem Backoff erneut versucht: 1 Minute, 5 Minuten, 30 Minuten, 2 Stunden, 12 Stunden.
  • Nach 5 aufeinanderfolgenden fehlgeschlagenen Zustellungen wird die Subscription automatisch deaktiviert.
  • Nach Auto-Disable: Endpoint reparieren, Subscription neu anlegen und das neue Signing-Secret sicher speichern.

Rate-Limits (tier-bezogen)

Pro API-Schlüssel werden zwei Buckets geprüft (Minute + Stunde). Limits hängen vom Tarif ab:

PlanAnfragen / MinuteAnfragen / StundeWebhook-Subscription-Limit
Starter305001
Standard6010003
Premium120300010
Platinum3001000025
Kanzlei3001000025

Bei Ausfall der Rate-Limit-Backends antwortet die API mit HTTP 503 + Retry-After (Fail-Closed). Tier-Lookup-Fehler fällt auf Starter-Limit zurück.

Erfolgreiche Antworten enthalten X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (Unix-Timestamp) und X-RateLimit-Tier (aktiver Plan).

Fehler

Fehlerantworten sind JSON und enthalten einen stabilen Code plus eine menschenlesbare Nachricht.

HTTPCodeBeschreibung
400INVALID_INPUTParameter oder JSON-Body sind ungültig.
401AUTH_UNAUTHORIZEDAPI-Key fehlt, ist ungültig oder wurde widerrufen.
403AUTH_FORBIDDENDer API-Key hat nicht die nötigen Rechte für diese Ressource.
404NOT_FOUNDDie Ressource existiert nicht im aktuellen Mandanten oder ist nicht sichtbar.
429rate_limit_exceededPlanabhängiges Rate-Limit überschritten. Nach kurzer Wartezeit erneut versuchen.
503rate_limit_backend_unavailableRate-Limit-Backend nicht verfügbar; API schlägt fail-closed fehl.

Typisches Format: { "error": "AUTH_UNAUTHORIZED", "message": "...", "request_id": "..." }.

Changelog

Öffentliche API-Änderungen werden hier versioniert dokumentiert.

  • 2026-05-08

    v1: Read-only Endpunkte für Rechnungen und Lieferanten, mandantenbezogene API-Keys und signierte Webhooks.

Nicht in v1 enthalten

Folgende Funktionen sind absichtlich noch nicht Teil der v1:

  • Schreib-Endpunkte (POST/PATCH/DELETE)
  • Steuerberater-Cross-Mandant-Zugriff (kommt in v2 nach echter Partner-Nachfrage)
  • Metered Billing (kommt mit dem hosted MCP Commercial Tier)
  • Separates Sandbox-Environment (eri_test_-Präfix ist reserviert)

Diese Website verwendet Cookies, um Ihre Erfahrung zu verbessern und den Datenverkehr zu analysieren. Sie können einzelne Kategorien jederzeit ablehnen. Datenschutzerklärung