Für Entwickler
Die Zentra-API.
Verbinden Sie Ihre Website, Ihren Shop oder Ihre Tools mit Zentra. Lesen Sie Ihre Daten, reichen Sie Entwürfe ein und werden Sie bei jeder bezahlten Rechnung benachrichtigt.
- Lesen in JSON
- Kunden, Artikel, Offerten, Aufträge, Rechnungen und Zahlungen über eine einfache REST-API.
- Nichts ohne Ihr Einverständnis
- Was Ihre Tools senden, kommt als Entwurf an. Sie geben es in der App frei.
- Inbegriffen
- In Solo, Team und Pro, ohne Aufpreis. 600 Aufrufe pro Stunde und Schlüssel.
Bevor Sie beginnen
- Öffnen Sie in der Zentra-App Einstellungen › API, Shops und Briefpost. Oder gehen Sie über Ihr Online-Konto.
- Erstellen Sie einen Schlüssel und geben Sie ihm einen Namen, zum Beispiel «Website». Wählen Sie «Lesen», oder «Lesen und Entwürfe», wenn Ihr Tool auch Anfragen einreichen soll.
- Kopieren Sie den Schlüssel sofort: Er beginnt mit zk_ und wird nicht mehr angezeigt. Bewahren Sie ihn wie ein Passwort auf, nur auf dem Server.
- Öffnen Sie Zentra auf einem Gerät des Unternehmens. Die App veröffentlicht dann die Daten, die die API lesen kann, und hält sie aktuell, solange sie geöffnet ist.
Nur der Inhaber und die Administratoren des Unternehmens erstellen und widerrufen Schlüssel. Ein widerrufener Schlüssel funktioniert sofort nicht mehr.
Ihre Daten bleiben in der App: Der Server speichert nur die zuletzt veröffentlichte Version dieser sechs Datensatztypen, für Unternehmen mit einem Schlüssel oder Webhook. Das Feld publishedAt jeder Antwort sagt, wann die App sie veröffentlicht hat.
Authentifizierung
Jeder Aufruf sendet den Schlüssel im Header Authorization. Alle Adressen beginnen mit:
https://zentraapp.ch/api/v1Beispielcurl https://zentraapp.ch/api/v1/invoices?status=issued&limit=20 \
-H "Authorization: Bearer zk_votre_cle"Die Antworten sind JSON in UTF-8 und werden nie zwischengespeichert. Rufen Sie die API nicht aus einem Browser auf: Der Schlüssel wäre sichtbar.
Ressourcen
Sechs Ressourcen, nur lesend. Jede lässt sich als Liste lesen oder einzeln über ihre ID.
/customers- Kunden
id, number, name, company, contactPerson, email, phone, addressLine1, addressLine2, postalCode, city, country, archived /articles- Artikel und Leistungen aus dem Katalog
id, kind, sku, name, description, unit, unitPriceCents, vatBp, trackStock, stockQuantityMilli, archived /quotes- Offerte
id, number, customerId, title, status, currency, issueDate, validUntil, subtotalCents, discountCents, vatCents, totalCents, lines /orders- Kundenaufträge
id, number, customerId, title, status, currency, orderDate, externalReference, totalCents, lines /invoices- Rechnungen
id, number, customerId, title, status, type, currency, issueDate, dueDate, subtotalCents, discountCents, vatCents, totalCents, paidCents, openCents, lines /payments- Erhaltene Zahlungen
id, invoiceId, date, amountCents, currency, method, reference
Offerten, Aufträge und Rechnungen enthalten ihre Positionen, mit position, articleId, description, quantityMilli, unit, unitPriceCents, discountBp, vatBp und totalCents. Jeder Datensatz trägt ausserdem updatedAt und changedAt.
Listen und Seiten
Listen sind nach Änderungsdatum sortiert. Um alles lückenlos zu übernehmen, folgen Sie nextCursor, solange hasMore true ist.
limit- Anzahl Ergebnisse pro Seite, von 1 bis 100. Standard 50.
cursor- Der Wert nextCursor der vorherigen Seite.
updated_since- Nur was sich seit diesem Datum geändert hat (ISO 8601 oder Unix-Zeitstempel).
status- Filter nach Status, zum Beispiel issued, paid oder draft.
customer_id- Nur die Dokumente eines Kunden.
include_deleted- true, um auch Löschungen zu erhalten, in der Form { id, deleted: true }.
{
"object": "list",
"entity": "invoices",
"data": [
{
"object": "invoice",
"id": "inv_8f2c",
"number": "2026-0142",
"customerId": "cus_51a0",
"status": "issued",
"currency": "CHF",
"issueDate": "2026-10-20",
"dueDate": "2026-11-19",
"totalCents": 129690,
"paidCents": 0,
"openCents": 129690,
"lines": [ … ],
"changedAt": "2026-10-20T09:14:03.000Z"
}
],
"hasMore": true,
"nextCursor": "c1_WzE3OTI…",
"publishedAt": "2026-10-26T07:55:12.000Z"
}Kunden synchronisieren// Node 18 ou plus récent : reprendre tout ce qui a changé depuis la dernière fois
const headers = { Authorization: `Bearer ${process.env.ZENTRA_API_KEY}` };
let url = 'https://zentraapp.ch/api/v1/customers?limit=100&include_deleted=true&updated_since=2026-10-01';
while (url) {
const response = await fetch(url, { headers });
if (!response.ok) throw new Error((await response.json()).error.message);
const page = await response.json();
for (const customer of page.data) console.log(customer.id, customer.name ?? 'supprimé');
url = page.nextCursor ? `https://zentraapp.ch/api/v1/customers?limit=100&include_deleted=true&cursor=${page.nextCursor}` : null;
}Beträge und Mengen
Alle Zahlen sind ganze Zahlen, von der App berechnet. Der Server rechnet nichts nach.
…Cents- Beträge in Rappen: 129690 = CHF 1’296.90.
…Milli- Mengen in Tausendsteln: 1000 = eine Einheit.
vatBp, discountBp- Sätze in Basispunkten: 100 = 1 %. Der MWST-Normalsatz lautet 810.
currency- CHF oder EUR.
openCents- Noch offener Betrag einer Rechnung.
Einen Entwurf einreichen
Ein Formular auf Ihrer Website kann eine Offertanfrage, einen Auftrag oder einen neuen Kunden anlegen. Der Entwurf kommt in der App an und wird freigegeben oder abgelehnt. Nichts wird ohne Sie gespeichert oder versendet.
POST /draftscurl -X POST https://zentraapp.ch/api/v1/drafts \
-H "Authorization: Bearer zk_votre_cle" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: site-demande-20261026-0042" \
-d '{
"kind": "quote",
"customer": { "name": "Marie Rochat", "email": "marie.rochat@example.ch" },
"reference": "Formulaire du site",
"note": "Pose prévue en novembre",
"lines": [
{ "sku": "RAD-600", "description": "Radiateur 600 W", "quantity": "3" },
{ "description": "Pose et mise en service", "quantity": "1.5" }
]
}'Antwort 202{ "object": "draft", "id": "in_3b9e…", "kind": "quote", "state": "pending", "duplicate": false }- Das Feld kind ist customer, quote oder order. Eine Offerte oder ein Auftrag hat 1 bis 200 Positionen.
- Geben Sie einen bestehenden Kunden über seine id an, oder seine Angaben: name, company, email, phone, addressLine1, addressLine2, postalCode, city, country.
- Jede Position hat eine Menge und einen sku, eine articleId oder eine Beschreibung. Allfällige Preise sind nur Hinweise: Die App wendet Ihren Katalog an und berechnet die Summen.
- Mit dem Header Idempotency-Key erzeugt ein wiederholter Versand nur einen Entwurf. Die Antwort zeigt dann duplicate: true.
- Um einen Entwurf zu verfolgen, lesen Sie /drafts/ gefolgt von seiner id: Der Status ist pending, imported oder rejected, mit der Referenz des erstellten Dokuments.
Webhooks
Zentra benachrichtigt Ihre https-Adresse bei jedem gewählten Ereignis. Fügen Sie den Webhook am selben Ort wie die Schlüssel hinzu. Sein Signaturgeheimnis beginnt mit whsec_ und wird nur einmal angezeigt.
customer.created- Ein Kunde wird angelegt.
quote.created- Eine Offerte wird ausgestellt.
quote.accepted- Eine Offerte wird angenommen.
order.created- Ein Auftrag wird bestätigt.
invoice.created- Eine Rechnung wird ausgestellt.
invoice.paid- Eine Rechnung ist vollständig bezahlt.
payment.created- Eine Zahlung wird erfasst.
draft.imported- Ein über die API eingereichter Entwurf wurde in der App freigegeben.
draft.rejected- Ein über die API eingereichter Entwurf wurde abgelehnt.
POST https://exemple.ch/zentra
Zentra-Event: invoice.paid
Zentra-Event-Id: evt_…
Zentra-Delivery-Id: dlv_…
Zentra-Signature: t=1793091600,v1=5d41c0…
{
"id": "evt_…",
"type": "invoice.paid",
"apiVersion": 1,
"createdAt": "2026-10-26T08:20:00.000Z",
"data": { "object": "invoice", "record": { "id": "inv_8f2c", "status": "paid", … } }
}Die Signatur ist ein hexadezimaler HMAC-SHA256, mit Ihrem Geheimnis über den Zeitstempel t, einen Punkt und den empfangenen Inhalt berechnet. Lehnen Sie Zeitstempel ab, die älter als fünf Minuten sind.
Signatur prüfen (Node)import { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody : le corps reçu, tel quel, avant tout JSON.parse
export function isFromZentra(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(signatureHeader.split(',').map((part) => part.split('=')));
const timestamp = Number(parts.t);
if (!Number.isInteger(timestamp) || Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const expected = createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex');
return parts.v1?.length === expected.length && timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}Abonnements über die API
Zapier, Make, n8n oder Ihr eigenes Werkzeug können ihre Webhooks mit dem API-Schlüssel anlegen und entfernen. GET /me prüft den Schlüssel und nennt das Unternehmen; GET /webhooks listet die Abonnements.
Abonnieren und abbestellenPOST https://zentraapp.ch/api/v1/webhooks
Authorization: Bearer zk_votre_cle
Content-Type: application/json
{ "url": "https://hooks.zapier.com/hooks/catch/…", "events": ["invoice.paid"] }
201 { "object": "webhook", "id": "whe_…", "events": ["invoice.paid"], "secret": "whsec_…" }
DELETE https://zentraapp.ch/api/v1/webhooks/whe_…- Antworten Sie innert zehn Sekunden mit einem 2xx-Code. Weiterleitungen werden nicht befolgt.
- Bei einem Fehler wird der Versand bis zu achtmal wiederholt: nach 1 Minute, 5 Minuten, 30 Minuten, dann nach 2, 6, 12 und 24 Stunden.
- Nach zwanzig Fehlern in Folge pausiert der Webhook. Die Schaltfläche «Fortsetzen» startet ihn wieder.
- Dasselbe Ereignis kann zweimal ankommen: Entfernen Sie Duplikate mit Zentra-Event-Id.
- Die Schaltfläche «Test senden» schickt ein ping-Ereignis.
KI-Assistenten (MCP)
Claude, ChatGPT oder jeder MCP-kompatible Assistent kann Ihre Zentra-Daten lesen. Er beantwortet «Wer schuldet mir noch Geld?» anhand der von der App berechneten Beträge.
In Claude, ohne Schlüssel
- Öffnen Sie in Claude die Einstellungen, dann Konnektoren, und wählen Sie «Benutzerdefinierten Konnektor hinzufügen». Bei einem Team- oder Enterprise-Abo fügt ein Inhaber der Claude-Organisation ihn hinzu.
- Nennen Sie ihn Zentra und fügen Sie die Serveradresse ein. Lassen Sie die erweiterten Einstellungen leer.
- Klicken Sie auf «Verbinden». Zentra öffnet sich: Melden Sie sich an, wählen Sie das Unternehmen und erlauben Sie den Zugriff.
- Öffnen Sie Zentra einmal auf einem Computer des Unternehmens. Die App veröffentlicht dann die Daten, die der Assistent liest.
https://zentraapp.ch/api/mcpNur Kontoinhaber und Administratoren können einen Assistenten verbinden, jeweils für ein Unternehmen. Verbundene Assistenten sind in Ihrem Konto unter Integrationen aufgeführt: Ein Klick trennt sie.
In Claude Code
Terminalclaude mcp add --transport http zentra https://zentraapp.ch/api/mcpStarten Sie danach /mcp in Claude Code und wählen Sie Zentra, um sich anzumelden.
Vorbereitete Fragen
Der Server bietet auch vorbereitete Fragen an. In Claude erscheinen sie im Menü «+» des Gesprächs.
qui_me_doit- Wer schuldet mir noch Geld?
ma_journee- Was steht heute an?
relances_semaine- Mahnungen der Woche vorbereiten
resume_mois- Meinen Monat zusammenfassen
creer_devis- Offerte erstellen
nouveau_client- Kunden hinzufügen
Mit einem API-Schlüssel
Ein Tool ohne Konto-Anmeldung kann einen API-Schlüssel verwenden, der im Header Authorization gesendet wird.
Konfiguration{
"mcpServers": {
"zentra": {
"type": "http",
"url": "https://zentraapp.ch/api/mcp",
"headers": { "Authorization": "Bearer zk_votre_cle" }
}
}
}search_customers- Sucht Kunden nach Name, Firma oder E-Mail.
get_customer- Ein Kunde und seine letzten Rechnungen.
list_invoices- Offene, fällige, bezahlte oder Entwurfsrechnungen.
get_invoice- Eine Rechnung mit ihren Positionen und Zahlungen.
list_quotes- Offerten nach Status und Kunde.
list_orders- Kundenaufträge.
search_articles- Katalogartikel mit Preis und Lagerbestand.
company_summary- Kennzahlen: offene und fällige Rechnungen, Anzahl Datensätze.
prepare_draft- Legt zur Freigabe einen Kunden, Lieferanten, Artikel, ein Projekt, eine Projektaufgabe, einen Termin, eine Offerte, einen Auftrag, eine Rechnung als Entwurf oder eine Notiz ab. Fehlt ein Detail, antwortet es mit den zu stellenden Fragen. Nur wenn Entwürfe erlaubt sind.
draft_requirements- Die Pflichtangaben jedes Entwurfs, mit der zu stellenden Frage.
search_projects- Projekte und Baustellen, um eine Aufgabe, einen Termin oder eine Notiz zuzuordnen.
search_suppliers- Lieferanten nach Name oder Kontakt.
list_autopilot_tasks- Die offenen Aufgaben im Autopiloten, mit den Aktionen, die der Assistent anfordern kann.
act_on_autopilot_task- Bestätigt eine Aufgabe auf Ihre Anfrage: einen Eintrag oder einen erhaltenen Entwurf anlegen, einen Termin hinzufügen, verschieben, ignorieren, eine Aufgabe als erledigt markieren. Nur wenn Sie bei der Verbindung «Autopilot-Aufgaben bestätigen» angekreuzt haben.
check_request- Sagt, ob ein Entwurf oder eine angeforderte Aktion von der App bereits verarbeitet wurde.
Der Assistent kann nichts senden, bezahlen oder löschen. Ein von ihm vorbereiteter Entwurf wartet in der App auf Ihre Freigabe, ausser Sie bitten ihn, ihn zu bestätigen.
Fehlt ein Detail, rät Zentra nicht: Ein Artikel ohne Preis, ein Kunde, der mehreren Einträgen ähnelt, oder ein unauffindbares Projekt gehen als Fragen an den Assistenten zurück, die er Ihnen vor dem Anlegen stellt.
Eine bestätigte Aktion wird von der Zentra-App ausgeführt, sobald sie auf einem Computer des Unternehmens geöffnet ist, und im Autopilot-Journal eingetragen. Eine E-Mail oder Mahnung senden, eine Zahlung erfassen, eine Rechnung ausstellen und eine Betreibung einleiten geschieht immer in der App.
Fehler und Grenzen
Ein Fehler liefert einen HTTP-Code und ein Objekt error mit einem stabilen Code und einer Meldung auf Französisch.
{ "error": { "code": "rate_limited", "message": "Trop d’appels pour cette clé. Réessayez dans une heure." } }- 400
invalid_query, invalid_draft, invalid_body - Die Anfrage ist fehlerhaft. Die Meldung nennt das zu korrigierende Feld.
- 401
unauthorized - Schlüssel fehlt, ist falsch kopiert oder widerrufen.
- 402
subscription_inactive - Das Abonnement des Unternehmens ist nicht mehr aktiv.
- 403
forbidden - Der Schlüssel kann nur lesen. Erstellen Sie einen Schlüssel «Lesen und Entwürfe».
- 404
not_found - Unbekannte Ressource oder ID.
- 405
method_not_allowed - Nur GET ist erlaubt, ausser POST auf drafts.
- 429
rate_limited - Mehr als 600 Aufrufe in der Stunde für diesen Schlüssel. Der Header Retry-After nennt die Wartezeit in Sekunden.
- 503
unavailable - Dienst vorübergehend nicht verfügbar. Versuchen Sie es später erneut.
Grenzen: 600 Aufrufe pro Stunde und Schlüssel, 100 Ergebnisse pro Seite, 64 KB pro Entwurf.
Shopify, WooCommerce oder die Briefpost verbindenTesten Sie die API mit Ihren Daten.
Vierzehn Tage kostenlos, API und Webhooks inklusive.
Ohne Kreditkarte. Keine automatische Zahlung.
