Zum Inhalt springen
Zentra
DemoGratis testen

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

  1. Öffnen Sie in der Zentra-App Einstellungen › API, Shops und Briefpost. Oder gehen Sie über Ihr Online-Konto.
  2. 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.
  3. 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.
  4. Ö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/v1
Beispiel
curl 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 }.
Beispielantwort
{
  "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 /drafts
curl -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.
Was Ihr Server erhält
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 abbestellen
POST 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

  1. Ö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.
  2. Nennen Sie ihn Zentra und fügen Sie die Serveradresse ein. Lassen Sie die erweiterten Einstellungen leer.
  3. Klicken Sie auf «Verbinden». Zentra öffnet sich: Melden Sie sich an, wählen Sie das Unternehmen und erlauben Sie den Zugriff.
  4. Öffnen Sie Zentra einmal auf einem Computer des Unternehmens. Die App veröffentlicht dann die Daten, die der Assistent liest.
Serveradresse
https://zentraapp.ch/api/mcp

Nur 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

Terminal
claude mcp add --transport http zentra https://zentraapp.ch/api/mcp

Starten 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 verbinden

Testen Sie die API mit Ihren Daten.

Vierzehn Tage kostenlos, API und Webhooks inklusive.

Ohne Kreditkarte. Keine automatische Zahlung.