savrsoft

API-Dokumentation

Eine einfache REST-API zum Lesen und Schreiben Ihrer Catering-Daten, plus signierte Webhooks für Echtzeit-Ereignisse. Erstellen Sie einen Schlüssel unter Entwickler in der App.

Authentifizierung

Alle API-Anfragen verwenden einen API-Schlüssel als Bearer-Token. Erstellen Sie einen in der App unter Entwickler → API-Schlüssel. Schlüssel sind entweder nur lesend oder lesen/schreiben.

curl https://savrsoft.com/api/v1/events \
  -H "Authorization: Bearer savr_live_your_key_here"

Basis-URL: https://savrsoft.com/api/v1 · Alle Antworten sind im JSON-Format. Fehler geben { "error": "…" } mit einem 4xx/5xx-Status zurück.

Statuscodes

CodeWann Sie ihn erhalten
200Erfolgreicher Lesevorgang.
201Erfolgreich erstellt. Der Inhalt lautet { "id": 42 } — rufen Sie den Datensatz ab, wenn Sie den Rest davon benötigen.
400Ein Pflichtfeld fehlt, z. B. { "error": "name is required" }, oder ein Paginierungs-Cursor konnte nicht gelesen werden.
401Kein API-Schlüssel, ein fehlerhafter oder ein widerrufener Schlüssel.
403Ein schreibgeschützter Schlüssel wurde für einen Schreibvorgang verwendet. Erstellen Sie einen Lese-/Schreibschlüssel unter Entwickler → API-Schlüssel.
404Der Datensatz existiert nicht oder gehört einer anderen Organisation an — beide Fälle sind bewusst nicht unterscheidbar. Dieselbe Antwort erfolgt auch bei einem unbekannten Pfad oder einer unbekannten Methode.

Umfang dieser API

Die API ist nur lesend und erstellend. Es gibt keine DELETE, PUT oder PATCH Endpunkte — eine Anfrage mit einer davon liefert 404 Unknown endpoint, genau wie bei jedem unbekannten Pfad. Löschen und Bearbeiten erfolgen in der App, sodass eine Integration die Datensätze eines Caterers nicht zerstören kann. Falls Sie über das Erstellen hinaus Schreibzugriff benötigen, Erzählen Sie uns, was Sie entwickeln.

Paginierung

Jeder Listen-Endpunkt ist paginiert. Übergeben Sie limit (Standard 100, maximal 500) und folgen Sie next_cursor bis has_more ist false:

{
  "data": [ ... ],
  "has_more": true,
  "next_cursor": "eyJuYW1lIjoiQWNtZSIsImlkIjo0Mn0"
}

Geben Sie den Cursor unverändert zurück, um die nächste Seite zu erhalten. Behandeln Sie ihn als undurchsichtig – die Kodierung kann sich ändern:

curl "https://savrsoft.com/api/v1/clients?limit=100&cursor=eyJuYW1lIjoiQWNtZSIsImlkIjo0Mn0" \
  -H "Authorization: Bearer savr_live_your_key_here"

Die Seitennavigation ist an der zuletzt empfangenen Zeile verankert, nicht an einem Offset – Zeilen, die während des Blätterns erstellt oder gelöscht werden, führen also nicht dazu, dass Sie einen Datensatz überspringen oder wiederholt sehen. Ein Cursor bleibt unbegrenzt gültig.

ParameterVerhalten
limit1–500. Fehlt der Wert, ist er null, negativ oder nicht numerisch, wird auf 100 zurückgesetzt; Werte über 500 werden auf 500 begrenzt.
cursornext_cursor aus der vorherigen Seite. Lassen Sie ihn für die erste Seite weg. Ein Cursor, der nicht gelesen werden kann – beschädigt oder von einem anderen Endpunkt – liefert 400 Invalid cursor statt stillschweigend von vorn zu beginnen.

Reihenfolge: /events und /invoices neueste zuerst; /recipes und /clients nach Name, wobei Gleichstände anhand der id aufgelöst werden, damit die Seitennavigation auch bei wiederholten Namen stabil bleibt.

Endpunkte

GET/v1/me

Ihre Organisation (id, name, currency).

GET/v1/events

Listet Events auf, neueste zuerst. Paginiert – siehe Pagination oben.

GET/v1/events/{id}

Eine Veranstaltung mit ihren Gerichten.

POST/v1/events · erfordert Lese-/Schreibrechte

Erstellen Sie eine Veranstaltung. Body:

{ "name": "Acme holiday party", "event_date": "2026-12-18",
  "guests": 120, "price_per_head": 55, "event_type": "corporate" }
GET/v1/recipes · GET/v1/recipes/{id}

Listet Rezepte auf (mit Allergenen & Ernährungshinweisen) oder zeigt ein einzelnes Rezept mit Zutaten. Die Liste ist paginiert und alphabetisch sortiert.

GET/v1/clients · POST/v1/clients

Listet Kunden auf (paginiert, nach Name) oder legt einen neuen an. Body zum Erstellen: { "name": "...", "email": "...", "phone": "...", "company": "..." }

GET/v1/invoices · GET/v1/invoices/{id}

Listet Rechnungen mit berechneten Summen auf, neueste zuerst, oder zeigt eine einzelne Rechnung mit Positionen. Die Liste ist paginiert.

Webhooks

Registrieren Sie einen Endpunkt unter Entwickler → Webhooks. Wir senden per POST eine JSON-Payload, sobald Ereignisse eintreten:

{
  "id": "evt_abc123",
  "type": "event.inquiry",
  "created_at": "2026-07-17T18:20:00.000Z",
  "data": { "id": 42, "name": "Corporate lunch — Dana Ruiz", ... }
}

Ereignistypen

TypAusgelöst bei
event.createdEin Event wird erstellt
event.inquiryEine neue Catering-Anfrage geht online ein
invoice.sentEine Rechnung wird als versendet markiert
invoice.paidEine Rechnung wird als bezahlt markiert
proposal.approvedEin Kunde genehmigt ein Angebot
client.createdEin Kunde wird angelegt

Signaturen prüfen

Jede Zustellung enthält einen x-savrsoft-signature Header: den HMAC-SHA256 des rohen Request-Bodys, signiert mit Ihrem Webhook-Signing-Secret. Berechnen Sie denselben Wert und vergleichen Sie:

// Node.js
const crypto = require('crypto');
const sig = crypto.createHmac('sha256', SIGNING_SECRET)
  .update(rawBody).digest('hex');
if (sig !== req.headers['x-savrsoft-signature']) reject();
Datenschutz · Sicherheit · AGB · Fragen? savrsoft.com · Catering-Integrationen in Minuten realisieren.