🔗Integrations

🔗 Verbinde Cowlendar mit deinem CRM, ERP oder deiner eigenen App (Public API & Webhooks)

Nutze die Public API und Webhooks von Cowlendar, um Buchungen mit deinem CRM, ERP oder eigenen Tools zu synchronisieren

20 min read
3 views
Updated May 22, 2026

Wenn Sie ein Unternehmen betreiben, das auf Buchungen angewiesen ist, benötigen Sie Ihre Buchungsdaten wahrscheinlich an mehr als einer Stelle. Ihr CRM muss wissen, wann ein neuer Kunde bucht. Ihr ERP benötigt die Umsatzdaten. Ihr Marketing-Tool muss eine Willkommens-E-Mail auslösen. Ihre benutzerdefinierte App muss Buchungen programmgesteuert erstellen.

Die Public API und Webhooks von Cowlendar machen all dies möglich. Mit der API können Sie Ihre Leistungen und Buchungen auslesen und aus jedem externen System neue Buchungen erstellen. Webhooks senden jedes Mal Echtzeitbenachrichtigungen an Ihren Server, wenn etwas passiert: eine Buchung wird erstellt, bestätigt, storniert, verschoben oder ein Abonnementereignis eintritt.

Beide Funktionen befinden sich derzeit in der Beta -Phase.

ℹ️Info
Die vollständige interaktive API-Referenz mit allen Schemata und Antwortbeispielen finden Sie unter https://app.cowlendar.com/public-api/docs

Was können Sie mit der Cowlendar-API erstellen?

Hier sind echte Integrationsszenarien, die Cowlendar-Händler derzeit erstellen:

Synchronisieren Sie jede Buchung mit HubSpot, Salesforce oder einem beliebigen CRM. Wenn ein Kunde einen Haarschnitt, einen Yoga-Kurs oder eine Vermietung bucht, wird sofort ein Webhook mit den vollständigen Buchungsdaten (Name, E-Mail, Telefon, Service, Datum, Preis, Teammitglied) ausgelöst. Ihr CRM erstellt oder aktualisiert den Kontakt automatisch, ohne manuelle Dateneingabe. Erstellen Sie Ihre eigene Buchungsseite oder Mobile-App. Verwenden Sie die API, um Ihre Dienste abzurufen, einschließlich Dauer, Teammitglieder, Ausrüstung und Teilnehmerkategorien, und Buchungen von Ihrem eigenen Frontend aus zu erstellen. Die Buchung löst dieselben Bestätigungs-E-Mails, SMS-Benachrichtigungen und die gleiche Google Calendar-Synchronisierung aus wie jede Buchung, die über das Cowlendar-Widget vorgenommen wird. Automatisieren Sie Arbeitsabläufe mit Zapier oder Make ohne Code. Richten Sie einen Cowlendar-Webhook auf Ihre Zapier- oder Make-Webhook-URL. Jedes Buchungsereignis wird zum Auslöser. Senden Sie eine Slack-Benachrichtigung, wenn jemand bucht, fügen Sie eine Zeile zu Google Sheets hinzu, erstellen Sie eine Trello-Karte oder lösen Sie eine E-Mail-Sequenz in Klaviyo oder Mailchimp aus. Füttern Sie Buchungsdaten in Ihr Berichts- oder BI-Tool. Verwenden Sie den Endpunkt „Buchungen auflisten“, um alle Buchungen innerhalb eines Datumsbereichs abzurufen, gefiltert nach Status, Service, Anwesenheit oder Kunden-E-Mail. Exportieren Sie für benutzerdefinierte Dashboards in Ihr Data Warehouse, Google Sheets oder Airtable. Buchungen mit Abonnement-Guthaben verknüpfen. Wenn Sie eine Buchung über API erstellen, übergeben Sie einen subscription_id, um automatisch ein Guthaben vom Plan des Kunden abzuziehen, zum Beispiel einen Yoga-Pass für 10 Stunden. Verbinden Sie POS- oder Admin-Buchungen mit externen Systemen. Webhooks werden für alle Buchungsquellen ausgelöst: das Storefront-Widget, das Admin-Panel, POS und die API selbst. Nichts fällt durchs Raster.

Authentifizierung

Für jede API-Anfrage ist ein Bearer-Token erforderlich, der von Ihrem Cowlendar-Administrator generiert wird. Tokens haben vollständigen Lese- und Schreibzugriff auf die Buchungen und Dienstleistungen Ihres Shops. Behandeln Sie sie wie Passwörter: Überweisen Sie sie nicht der Versionskontrolle und teilen Sie sie nicht in öffentlichen Kanälen.

So generieren Sie Ihr API-Token

Schritt 1: Öffnen Sie in Ihrem Shopify-Administrator die App Cowlendar.

Schritt 2: Gehen Sie zu Settings > Public API.

Schritt 3: Klicken Sie auf Generate token.

Schritt 4: Geben Sie Ihrem Token einen aussagekräftigen Namen, damit Sie ihn später identifizieren können, zum Beispiel „HubSpot sync“, „Zapier“ oder „Mobile app“.

Schritt 5: Klicken Sie auf Generate . Cowlendar zeigt Ihnen einmalig den vollständigen Token. Kopieren Sie es sofort und speichern Sie es an einem sicheren Ort wie einem Passwort-Manager oder den Umgebungsvariablen Ihres Servers.

Sie können jedes Token jederzeit auf derselben Seite widerrufen. Das Widerrufen eines Tokens stoppt sofort alle API-Anfragen, die es verwenden.

Mit Ihrem Token

Fügen Sie das Token in den Authorization-Header jeder API-Anfrage ein:

Authorization: Bearer YOUR_TOKEN_HERE

Beispiel mit Curl:

curl https://app.cowlendar.com/public-api/v1/services -H "Authorization: Bearer YOUR_TOKEN_HERE"

Wenn das Token fehlt oder ungültig ist, gibt die API 401 zurück.

API-Endpunkte

Basis-URL: https://app.cowlendar.com

Dienste auflisten

GET /public-api/v1/services

Gibt alle nicht archivierten Services in Ihrem Shop zurück. Verwenden Sie diesen Endpunkt, um Ihre Service-IDs, -Typen, -Dauer, Teammitglieder, Ausrüstung und Teilnehmerkategorien zu ermitteln, bevor Sie Buchungen über die API erstellen.

Abfrageparameter:

limit (optional, 1-100): Anzahl der Ergebnisse pro Seite.

cursor (optional): Paginierungscursor aus einer vorherigen Antwort.

is_active (optional, wahr oder falsch): Filtern Sie nach aktiven oder inaktiven Diensten.

type (optional): Nach Diensttyp filtern. Werte: classic-checkout, classic-no-checkout, multiday-checkout, multiday-no-checkout, multislot-checkout, multislot-no-checkout, fullday-checkout, fullday-no-checkout.

q (optional, max. 120 Zeichen): Dienste nach Titel suchen.

sort (optional): -id (Standard, Neueste zuerst), id (Älteste zuerst), title (A bis Z), -title (Z bis A).

Beispielanfrage:

curl "https://app.cowlendar.com/public-api/v1/services?is_active=true&limit=10" -H "Authorization: Bearer YOUR_TOKEN_HERE"

Beispielantwort (gekürzt):

{
 "data": [
 {
 "id": "6789abcdef0123456789abcd",
 "title": "Haircut",
 "type": "classic-checkout",
 "is_active": true,
 "timezone": "Europe/Paris",
 "durations": [30, 45, 60],
 "default_duration": 30,
 "avs_type": "teammates",
 "meeting_location": "in_person",
 "enable_participants": false,
 "participants": [],
 "equipments": [],
 "teammates": [
 {
 "id": "aaa111bbb222ccc333ddd444",
 "firstname": "Marie",
 "lastname": "Dupont",
 "email": "[email protected]",
 "thumbnail": null
 }
 ],
 "product": {
 "handle": "haircut",
 "title": "Haircut",
 "image": "https://cdn.shopify.com/..."
 },
 "created_at": "2025-09-01T10:00:00.000Z",
 "updated_at": "2026-05-10T08:30:00.000Z"
 }
 ],
 "pagination": {
 "has_more": false,
 "next_cursor": null
 }
}

Grundlegende Servicebereiche verstehen

avs_type zeigt Ihnen, wie dieser Dienst die Verfügbarkeit verwaltet und bestimmt, ob Sie beim Erstellen von Buchungen einen teammate_id übergeben müssen:

avs_type: "teammates" bedeutet, dass jedes Teammitglied seinen eigenen unabhängigen Zeitplan hat. Übergeben Sie beim Erstellen einer Buchung einen teammate_id aus dem Array teammates. Wenn Sie es weglassen, wird der Shop-Inhaber als Fallback verwendet.

avs_type: "service" bedeutet, dass der Dienst selbst über seine Verfügbarkeit verfügt. Das zugewiesene Teammitglied wird automatisch aus dem Buchungszeitpunkt ermittelt. Sie können weiterhin ein teammate_id übergeben, um die Zuweisung einer bestimmten Person zu erzwingen.

avs_type: "equipment" bedeutet, dass die Verfügbarkeit pro Gerät gilt. Ähnlich dem Servicemodus, jedoch an die Gerätekapazität gebunden.

enable_participants gibt Ihnen Auskunft darüber, ob der Dienst typisierte Teilnehmerkategorien wie „Erwachsener“, „Kind“ oder „Senior“ verwendet. Bei true enthält das Array participants die Kategorien mit ihren IDs, Mindest- und Höchstmengen sowie Standardwerten. Diese IDs benötigen Sie beim Anlegen von Buchungen mit detaillierter Teilnehmeraufschlüsselung. Ausrüstung enthält buchbare Ressourcen wie Räume, Plätze, Fahrzeuge oder Fahrräder mit ihren Varianten und SKUs. Bei Geräten mit tracking_type: "same" sind alle Einheiten austauschbar und Sie können jede SKU verwenden, normalerweise base. Für tracking_type: "unique" hat jede Einheit ihre eigene SKU und Sie müssen zwischen variants[].sku auswählen. Typ gibt Ihnen das Buchungsmodell an. Das Suffix -checkout oder -no-checkout gibt an, ob der Dienst den Shopify-Checkout verwendet. Das Präfix gibt das Planungsmodell an: classic für ein einzelnes Zeitfenster, multiday für mehrere Tage wie Hotelaufenthalte, multislot für mehrere aufeinanderfolgende Zeitfenster und fullday für eine ganztägige Buchung.

Buchungen auflisten

GET /public-api/v1/bookings

Gibt Buchungen für Ihren Shop zurück. Dies ist der Endpunkt, den Sie für CRM-Synchronisierungen, Berichtsexporte und benutzerdefinierte Buchungs-Dashboards verwenden.

Abfrageparameter:

limit (optional, 1-100): Ergebnisse pro Seite.

cursor (optional): Paginierungscursor.

start (optional, ISO 8601 datetime): Nur Buchungen, die an oder nach diesem Datum beginnen.

end (optional, ISO 8601 datetime): nur Buchungen, die vor diesem Datum beginnen.

service_id (optional, Array von IDs): Filtern Sie nach einem oder mehreren Diensten.

subscription_id (optional, Array von IDs): Nach Abonnements filtern.

status (optional, Array): confirmed, pending, declined, canceled.

attendance (optional, Array): booked, pending, arrived, started, completed, no-show, delayed, paid.

customer_email (optional): Filtern Sie nach der genauen E-Mail-Adresse des Kunden.

sort (optional): -id (Standard, Neueste zuerst), id (Älteste zuerst), start_date (Älteste zuerst), -start_date (Neueste zuerst).

Beispiel: Erhalten Sie alle bestätigten Buchungen für nächste Woche:

curl "https://app.cowlendar.com/public-api/v1/bookings?status=confirmed&start=2026-05-25T00:00:00Z&end=2026-06-01T00:00:00Z&sort=start_date" -H "Authorization: Bearer YOUR_TOKEN_HERE"

Beispiel: Alle Buchungen für einen bestimmten Kunden finden:

curl "https://app.cowlendar.com/public-api/v1/[email protected]" -H "Authorization: Bearer YOUR_TOKEN_HERE"

Beispiel: Alle Nichterscheinen eines bestimmten Dienstes exportieren:

curl "https://app.cowlendar.com/public-api/v1/bookings?attendance=no-show&service_id=6789abcdef0123456789abcd" -H "Authorization: Bearer YOUR_TOKEN_HERE"

Beispielantwort (gekürzt):

{
 "data": [
 {
 "id": "abc123def456ghi789jkl012",
 "booking_str": "COW-1234",
 "service": {
 "id": "6789abcdef0123456789abcd",
 "title": "Haircut",
 "type": "classic-checkout"
 },
 "start_date": "2026-05-27T14:00:00.000Z",
 "end_date": "2026-05-27T14:30:00.000Z",
 "timezone": "Europe/Paris",
 "customer": {
 "name": "Jane Smith",
 "email": "[email protected]",
 "phone": "+33612345678",
 "locale": "en"
 },
 "form_data": {
 "Special requests": "Window seat"
 },
 "quantity": 1,
 "unit_quantity": 1,
 "quantity_details": [],
 "price": { "amount": 35, "currency": "EUR" },
 "confirmation_status": "confirmed",
 "attendance": "booked",
 "financial_status": "paid",
 "is_canceled": false,
 "teammates": [
 {
 "id": "aaa111bbb222ccc333ddd444",
 "firstname": "Marie",
 "lastname": "Dupont"
 }
 ],
 "order_id": "gid://shopify/Order/123456789",
 "subscription_id": null,
 "created_at": "2026-05-20T09:15:00.000Z",
 "updated_at": "2026-05-20T09:15:00.000Z"
 }
 ],
 "pagination": {
 "has_more": false,
 "next_cursor": null
 }
}

Grundlegende Buchungsfelder verstehen

quantity und unit_quantity arbeiten zusammen. Bei einer klassischen Dienstleistung wie einem Haarschnitt ist quantity die Anzahl der anwesenden Kunden und unit_quantity ist 1. Bei einem mehrtägigen Service wie einem Hotelaufenthalt ist quantity die Anzahl der Zimmer und unit_quantity die Anzahl der Nächte. Bei einem Multislot-Dienst ist quantity immer 1 und unit_quantity die Anzahl der gebuchten Slots. Die gesamten abrechenbaren Einheiten betragen immer quantity x unit_quantity. quantity_details ist die detaillierte Aufschlüsselung. Es kann drei Arten von Einträgen enthalten: default für eine anonyme Zählung, participant für einen typisierten Teilnehmer wie „Erwachsener“ oder „Kind“ oder equipment für eine buchbare Ressource wie „Court 3“. Ältere Buchungen haben hier möglicherweise ein leeres Array. Bestätigungsstatus ist confirmed, pending oder declined. Einige Dienste erfordern eine manuelle Bestätigung durch den Administrator, bevor eine Buchung aktiv wird. Anwesenheit verfolgt den Anwesenheitslebenszyklus des Kunden: booked, pending, arrived, started, completed, no-show, delayed, paid. order_id ist die Shopify-Bestell-ID, als die Buchung den Shopify-Checkout durchlaufen hat. Es ist null für manuelle Buchungen und über die API erstellte Buchungen. subscription_id verknüpft die Buchung mit einem Abonnement, beispielsweise einem 10-Klassen-Pass.

Erstellen Sie eine Buchung über die API

POST /public-api/v1/bookings

Erstellt programmgesteuert eine Buchung. Dies wird als manuelle Buchung behandelt, was bedeutet, dass keine Shopify-Bestellung erstellt wird. Alle üblichen Automatisierungen werden jedoch weiterhin normal ausgelöst: Bestätigungs-E-Mails an den Kunden, Benachrichtigungs-E-Mails und SMS an das Team sowie Kalendersynchronisierung mit Google Calendar oder Outlook.

Diesen Endpunkt verwenden Sie beim Erstellen eines benutzerdefinierten Buchungs-Frontends, eines Mobile-App, eines Kiosks oder beim Importieren von Buchungen aus einem anderen System.

Erforderliche Felder:

service_id (String): die ID des Dienstes, die Sie von List Services erhalten.

start_date (ISO 8601 datetime): wann die Buchung beginnt.

end_date (ISO 8601 datetime): wann die Buchung endet.

timezone (Zeichenfolge): IANA-Zeitzone, zum Beispiel Europe/Paris, America/New_York, Asia/Tokyo.

customer (Objekt): muss mindestens email oder phone enthalten. Es kann auch name, firstname, lastname und locale enthalten, was der Sprachcode für die Benachrichtigungs-E-Mails des Kunden ist.

Optionale Felder:

quantity (Ganzzahl, Standard 1): Gebuchte Einheiten der obersten Ebene. Wird ignoriert, wenn quantity_details bereitgestellt wird.

unit_quantity (Ganzzahl, Standard 1): Untereinheiten pro Einheit der obersten Ebene.

quantity_details (Array): Detaillierte Aufschlüsselung nach Teilnehmertyp oder Ausrüstung. Wenn angegeben, wird quantity automatisch als Summe berechnet.

teammate_id (Zeichenfolge): Erzwingen Sie die Zuweisung eines bestimmten Teammitglieds.

subscription_id (Zeichenfolge): Verknüpfen Sie diese Buchung mit einem bestehenden Abonnement und ziehen Sie ein Guthaben ab.

form_data (Objekt): Benutzerdefinierte Schlüssel- oder Wertepaare aus Ihrem Buchungsformular.

price (Zahl, Standard 0): Netto-Gesamtpreis für die Buchung.

currency (Zeichenfolge): ISO 4217-Code wie USD, EUR oder GBP. Standardmäßig wird die Währung Ihres Shops verwendet.

Beispiel: Erstellen Sie eine einfache Buchung

Ein Kunde bucht einen 30-minütigen Haarschnitt bei einem bestimmten Stylisten:

curl -X POST https://app.cowlendar.com/public-api/v1/bookings -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Content-Type: application/json" -d '{
 "service_id": "6789abcdef0123456789abcd",
 "start_date": "2026-06-01T10:00:00.000Z",
 "end_date": "2026-06-01T10:30:00.000Z",
 "timezone": "Europe/Paris",
 "customer": {
 "email": "[email protected]",
 "name": "John Doe",
 "phone": "+33612345678",
 "locale": "en"
 },
 "teammate_id": "aaa111bbb222ccc333ddd444",
 "quantity": 1,
 "price": 35,
 "currency": "EUR"
}'

Cowlendar erstellt die Buchung und löst die Bestätigungs-E-Mail, SMS und Kalendereinladung sowohl für den Kunden als auch für das Teammitglied aus.

Beispiel: Gruppenbuchung mit eingegebenen Teilnehmern

Eine Familie bucht eine Führung: 3 Erwachsene und 2 Kinder zu unterschiedlichen Preisen:

curl -X POST https://app.cowlendar.com/public-api/v1/bookings -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Content-Type: application/json" -d '{
 "service_id": "6789abcdef0123456789abcd",
 "start_date": "2026-06-15T09:00:00.000Z",
 "end_date": "2026-06-15T11:00:00.000Z",
 "timezone": "America/New_York",
 "customer": {
 "email": "[email protected]",
 "firstname": "Sarah",
 "lastname": "Miller",
 "phone": "+15551234567",
 "locale": "en"
 },
 "quantity_details": [
 {
 "type": "participant",
 "name": "Adult",
 "quantity": 3,
 "participant_id": "adult_id_from_service"
 },
 {
 "type": "participant",
 "name": "Child (under 12)",
 "quantity": 2,
 "participant_id": "child_id_from_service"
 }
 ],
 "price": 175,
 "currency": "USD"
}'

Die participant_id-Werte stammen aus dem participants[]-Array des Dienstes in der List Services-Antwort. Der Gesamtwert quantity wird automatisch auf 5 (3 + 2) gesetzt.

Beispiel: Buchung mit Ausrüstung

Ein Kunde bucht einen Tennisplatz für 1 Stunde:

curl -X POST https://app.cowlendar.com/public-api/v1/bookings -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Content-Type: application/json" -d '{
 "service_id": "6789abcdef0123456789abcd",
 "start_date": "2026-06-10T16:00:00.000Z",
 "end_date": "2026-06-10T17:00:00.000Z",
 "timezone": "Europe/London",
 "customer": {
 "email": "[email protected]",
 "name": "Tom Wilson"
 },
 "quantity_details": [
 {
 "type": "equipment",
 "name": "Court 3",
 "quantity": 1,
 "equipment_id": "eee555fff666ggg777hhh888",
 "equipment_sku": "COURT3",
 "capacity": 4
 }
 ],
 "price": 25,
 "currency": "GBP"
}'

equipment_id und equipment_sku stammen aus dem equipments[]-Array des Dienstes. Für Geräte mit tracking_type: "same" verwenden Sie eine beliebige SKU, typischerweise base. Verwenden Sie für tracking_type: "unique" den spezifischen variants[].sku für das gewünschte Gerät.

Beispiel: Abo-gebundene Buchung

Ein Yoga-Studio-Mitglied verwendet ein Guthaben von seinem monatlichen 10-Stunden-Pass:

curl -X POST https://app.cowlendar.com/public-api/v1/bookings -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Content-Type: application/json" -d '{
 "service_id": "6789abcdef0123456789abcd",
 "start_date": "2026-06-05T08:00:00.000Z",
 "end_date": "2026-06-05T09:00:00.000Z",
 "timezone": "America/Los_Angeles",
 "customer": {
 "email": "[email protected]",
 "name": "Lisa Chen",
 "locale": "en"
 },
 "subscription_id": "fff000eee111ddd222ccc333",
 "price": 0
}'

Das Abonnement muss active lauten, zum selben Dienst gehören und remaining_credits > 0 haben. Cowlendar verringert automatisch das Guthaben und sendet die E-Mail mit der Aktualisierung des Abonnements an den Kunden.

Fehlercodes

400 Validierungsfehler. Ein erforderliches Feld fehlt oder hat das falsche Format. Der Fehlertext teilt Ihnen mit, um welches Feld es sich handelt.

401 Fehlendes oder ungültiges Token.

403 Shop ist inaktiv oder der Zugriff ist eingeschränkt.

404 Dienst nicht gefunden.

422 Buchung abgelehnt. Das Zeitfenster ist bereits belegt, das Teammitglied ist nicht verfügbar, die Ausrüstung ist ausgelastet oder das Abonnement hat keine Restguthaben mehr. Überprüfen Sie die Fehlermeldung auf den konkreten Grund.

429 Ratenlimit überschritten. Platzieren Sie Ihre Anfragen und versuchen Sie es nach einem Moment noch einmal.

Paginierung

Alle Listenendpunkte verwenden die Cursor-basierte Paginierung. Wenn die Antwort "has_more": true enthält, übergeben Sie den Wert next_cursor als Parameter cursor in Ihrer nächsten Anfrage:

curl "https://app.cowlendar.com/public-api/v1/bookings?cursor=eyJpZCI6IjY3ODlhYmNkIn0=&limit=50" -H "Authorization: Bearer YOUR_TOKEN_HERE"

Die Sortierreihenfolge bleibt seitenübergreifend erhalten. Die maximale Seitengröße beträgt 100 Ergebnisse.

Webhooks: Buchungsbenachrichtigungen in Echtzeit

Während Sie mit der API Daten bei Bedarf abrufen können, übertragen Webhooks die Daten sofort an Sie. Jedes Mal, wenn eine Buchung erstellt, bestätigt, storniert oder verschoben wird, sendet Cowlendar einen signierten HTTP-POST an die von Ihnen konfigurierte URL.

Webhooks sind für den Aufbau von Echtzeitintegrationen unerlässlich: CRM-Synchronisierungen, Slack-Benachrichtigungen, automatisierte E-Mail-Sequenzen, Live-Dashboards oder alle Workflows, die auf Buchungsereignisse reagieren müssen, sobald diese eintreten.

Richten Sie einen Webhook-Endpunkt ein

Schritt 1: Öffnen Sie in Ihrem Shopify-Administrator die App Cowlendar.

Schritt 2: Gehen Sie zu Settings > Webhooks.

Schritt 3: Klicken Sie auf Add endpoint.

Schritt 4: Geben Sie einen Namen für Ihren Endpunkt ein, zum Beispiel „HubSpot CRM“, „Zapier“ oder „Analytics pipeline“.

Schritt 5: Fügen Sie Ihre HTTPS-URL ein. Die URL muss HTTPS verwenden. Wenn Sie Zapier oder Make verwenden, fügen Sie die von ihnen bereitgestellte Webhook-URL ein.

Schritt 6: Markieren Sie die Ereignisse, die Sie erhalten möchten. Sie können eine beliebige Kombination auswählen.

Schritt 7: Klicken Sie auf Create.

Cowlendar zeigt ein Signaturgeheimnis an, das mit whsec_ beginnt. Kopieren Sie es sofort und bewahren Sie es sicher auf. Dieses Geheimnis wird nur einmal angezeigt und Sie benötigen es, um eingehende Webhook-Anfragen auf Ihrem Server zu überprüfen.

Sie können jeden Endpunkt später bearbeiten, um die URL zu ändern oder bestimmte Ereignisse zu aktivieren oder zu deaktivieren:

Die 8 Webhook-Ereignisse

booking.created wird ausgelöst, wenn eine neue Buchung aus einer beliebigen Quelle erstellt wird: dem Storefront-Widget, dem Admin-Panel, POS oder der öffentlichen API. booking.confirmed wird ausgelöst, wenn eine ausstehende Buchung manuell vom Administrator bestätigt wird. booking.declined wird ausgelöst, wenn eine ausstehende Buchung abgelehnt wird. booking.canceled wird ausgelöst, wenn eine Buchung vom Kunden oder Administrator storniert wird. booking.rescheduled wird ausgelöst, wenn das Datum einer Buchung oder zugewiesene Teammitglieder geändert werden. booking.attendance_changed wird ausgelöst, wenn sich der Anwesenheitsstatus ändert, beispielsweise von „gebucht“ auf „abgeschlossen“ oder wenn er als „Nichterscheinen“ markiert wird. subscription.created wird ausgelöst, wenn ein neues wiederkehrendes Abonnement erstellt wird. subscription.billing_failed wird ausgelöst, wenn ein Abonnementabrechnungsversuch fehlschlägt. Nach drei aufeinanderfolgenden Fehlern wird der Abonnementvertrag auf Shopify automatisch gekündigt und der lokale Status ändert sich in canceled.

Wie eine Webhook-Nutzlast aussieht

Bei jeder Webhook-Übermittlung handelt es sich um einen HTTP-POST mit einem JSON-Body. Hier ist ein vollständiges booking.created-Beispiel:

{
 "id": "evt_2b86f80a-1c3d-4e5f-9a8b-7c6d5e4f3a2b",
 "type": "booking.created",
 "created_at": "2026-05-20T09:15:00.000Z",
 "shop_domain": "yourshop.myshopify.com",
 "data": {
 "id": "abc123def456ghi789jkl012",
 "booking_str": "COW-1234",
 "service": {
 "id": "6789abcdef0123456789abcd",
 "title": "Haircut",
 "type": "classic-checkout"
 },
 "start_date": "2026-05-27T14:00:00.000Z",
 "end_date": "2026-05-27T14:30:00.000Z",
 "timezone": "Europe/Paris",
 "customer": {
 "name": "Jane Smith",
 "email": "[email protected]",
 "phone": "+33612345678",
 "locale": "en"
 },
 "form_data": {},
 "quantity": 1,
 "unit_quantity": 1,
 "quantity_details": [],
 "price": { "amount": 35, "currency": "EUR" },
 "confirmation_status": "confirmed",
 "attendance": "booked",
 "financial_status": null,
 "is_canceled": false,
 "teammates": [
 {
 "id": "aaa111bbb222ccc333ddd444",
 "firstname": "Marie",
 "lastname": "Dupont"
 }
 ],
 "order_id": null,
 "subscription_id": null,
 "created_at": "2026-05-20T09:15:00.000Z",
 "updated_at": "2026-05-20T09:15:00.000Z"
 }
}

Das Feld data enthält das vollständige Buchungs- oder Abonnementobjekt in genau derselben Struktur wie die API-Antwort.

Bei subscription.billing_failed-Ereignissen umfasst die Nutzlast ein zusätzliches previous-Objekt mit dem failure_count vor dem aktuellen Versuch, sodass Sie die Eskalation verfolgen können, indem Sie beispielsweise nach dem zweiten Fehlschlag eine dringende E-Mail senden.

Fordern Sie Header bei jeder Webhook-Zustellung an

X-Cowlendar-Event-Id ist die eindeutige ID des Ereignisses. Cowlendar verwendet dieselbe ID erneut, wenn eine fehlgeschlagene Zustellung erneut versucht wird. Nutzen Sie es zur Deduplizierung auf Ihrer Seite.

X-Cowlendar-Event-Type ist die Ereignistypzeichenfolge, zum Beispiel booking.created.

X-Cowlendar-Timestamp ist der Unix-Zeitstempel in Sekunden, als Cowlendar die Anfrage signiert hat.

X-Cowlendar-Signature ist die HMAC-SHA256-Signatur im Format t=<timestamp>,v1=<hex>.

Überprüfen Sie die Webhook-Signatur

Jede Webhook-Anfrage ist signiert, sodass Sie bestätigen können, dass sie tatsächlich von Cowlendar stammt und nicht manipuliert wurde. Die Signatur wird als HMAC-SHA256(secret, timestamp + "." + raw_body) unter Verwendung des Signaturgeheimnisses Ihres Endpunkts berechnet.

Sie sollten auch Anfragen mit einem Zeitstempel ablehnen, der älter als 5 Minuten ist, um Replay-Angriffe zu verhindern.

⚠️Warning
Berechnen Sie die Signatur immer über den RAW-Anfragetext, die genauen gesendeten Bytes Cowlendar, nicht über ein analysiertes und erneut serialisiertes JSON-Objekt. Durch das Parsen und erneute Serialisieren können Leerzeichen oder die Schlüsselreihenfolge geändert werden, wodurch die Signatur beschädigt wird.

Node.js (Express):

import crypto from "crypto";
import express from "express";

const app = express();

app.post(
 "/webhooks/cowlendar",
 express.raw({ type: "application/json" }),
 (req, res) => {
 const sigHeader =
 req.header("X-Cowlendar-Signature") || "";
 const timestamp =
 req.header("X-Cowlendar-Timestamp") || "";
 const rawBody = req.body.toString("utf8");

 // Reject requests older than 5 minutes
 if (
 Math.abs(Date.now() / 1000 - parseInt(timestamp, 10))
 > 300
 ) {
 return res.status(400).send("Timestamp too old");
 }

 const expected = crypto
 .createHmac(
 "sha256",
 process.env.COWLENDAR_WEBHOOK_SECRET
 )
 .update(`${timestamp}.${rawBody}`)
 .digest("hex");

 const received = sigHeader
 .split(",")
 .find((p) => p.startsWith("v1="))
 ?.slice(3);

 if (
 !received ||
 !crypto.timingSafeEqual(
 Buffer.from(expected),
 Buffer.from(received)
 )
 ) {
 return res.status(401).send("Invalid signature");
 }

 const event = JSON.parse(rawBody);

 // Short-circuit test pings
 if (event.type === "webhook.ping") {
 return res.status(200).send("pong");
 }

 // Handle real events here
 res.status(200).send("ok");
 }
);

Python (Flasche):

import hmac, hashlib, os, time, json
from flask import Flask, request

app = Flask(__name__)

@app.post("/webhooks/cowlendar")
def cowlendar_webhook():
 sig_header = request.headers.get(
 "X-Cowlendar-Signature", ""
 )
 timestamp = request.headers.get(
 "X-Cowlendar-Timestamp", ""
 )
 raw_body = request.get_data(as_text=True)

 # Reject requests older than 5 minutes
 if abs(time.time() - int(timestamp)) > 300:
 return "Timestamp too old", 400

 expected = hmac.new(
 os.environ["COWLENDAR_WEBHOOK_SECRET"].encode(),
 f"{timestamp}.{raw_body}".encode(),
 hashlib.sha256,
 ).hexdigest()

 received = next(
 (p[3:] for p in sig_header.split(",")
 if p.startswith("v1=")),
 None,
 )
 if not received or not hmac.compare_digest(
 expected, received
 ):
 return "Invalid signature", 401

 event = json.loads(raw_body)

 if event["type"] == "webhook.ping":
 return "pong", 200

 # Handle real events here
 return "ok", 200

PHP:

<?php
$secret = getenv("COWLENDAR_WEBHOOK_SECRET");

$rawBody = file_get_contents("php://input");
$sigHeader = $_SERVER["HTTP_X_COWLENDAR_SIGNATURE"] ?? "";
$timestamp = $_SERVER["HTTP_X_COWLENDAR_TIMESTAMP"] ?? "";

// Reject requests older than 5 minutes
if (abs(time() - (int)$timestamp) > 300) {
 http_response_code(400);
 exit("Timestamp too old");
}

$expected = hash_hmac(
 "sha256",
 $timestamp . "." . $rawBody,
 $secret
);

$received = null;
foreach (explode(",", $sigHeader) as $part) {
 if (str_starts_with($part, "v1=")) {
 $received = substr($part, 3);
 break;
 }
}

if (!$received || !hash_equals($expected, $received)) {
 http_response_code(401);
 exit("Invalid signature");
}

$event = json_decode($rawBody, true);

if ($event["type"] === "webhook.ping") {
 http_response_code(200);
 exit("pong");
}

// Handle real events here
http_response_code(200);
echo "ok";

Testen Sie Ihren Webhook, bevor Sie ihn live schalten

Jeder Webhook-Endpunkt verfügt über eine Test -Schaltfläche im Admin. Wenn Sie darauf klicken, wird ein synthetisches webhook.ping-Ereignis an Ihre URL gesendet. Dieses Ereignis verwendet dasselbe Signierungs-, Header- und Wiederholungsverhalten wie echte Ereignisse, jedoch mit einer harmlosen Testnutzlast:

{
 "id": "evt_2b86f80a...",
 "type": "webhook.ping",
 "created_at": "2026-05-13T14:57:57.704Z",
 "shop_domain": "yourshop.myshopify.com",
 "data": {
 "message": "This is a test event from Cowlendar. If you can read this, your endpoint is reachable."
 }
}

Verwenden Sie dies, um zu bestätigen, dass Cowlendar Ihre URL erreichen kann, dass DNS-, HTTPS- und Firewall-Einstellungen funktionieren, und um Ihren HMAC-Signatur-Verifizierungscode zu validieren, ohne eine echte Buchung zu erstellen. Bei einer echten Buchung würden E-Mails an einen Kunden gesendet, Kalenderereignisse erstellt und möglicherweise eine Shopify-Bestellung ausgelöst.

Nachdem Sie auf „Testen“ geklickt haben, überprüfen Sie die Schaltfläche See deliveries, um den HTTP-Statuscode anzuzeigen, den Ihr Endpunkt zurückgegeben hat. Ein grüner 200 bedeutet, dass alles funktioniert.

Verhalten wiederholen und automatisch deaktivieren

Wenn Ihr Endpunkt einen 5xx-Fehler, einen 429 oder eine Netzwerk-Zeitüberschreitung zurückgibt, versucht Cowlendar es nach diesem Zeitplan erneut:

Nach 1 Minute, nach 5 Minuten, nach 25 Minuten, nach 2 Stunden, nach 10 Stunden, nach 50 Stunden. Das sind insgesamt 6 Versuche über einen Zeitraum von etwa 3 Tagen.

Nach etwa 20 aufeinanderfolgenden Ausfällen bei allen Ereignissen wird der Endpunkt automatisch deaktiviert und Cowlendar sendet eine E-Mail an den Shop-Inhaber. Sie können den Endpunkt über Settings > Webhooks wieder aktivieren, sobald Ihr Server wieder online ist.

Bei Wiederholungsversuchen wird derselbe X-Cowlendar-Event-Id wiederverwendet. Speichern Sie verarbeitete Ereignis-IDs immer und überspringen Sie Duplikate.

Jede 2xx-Antwort gilt als Erfolg. Sie müssen keinen bestimmten Textkörper oder Inhaltstyp zurückgeben.

Best Practices für Webhooks

Reagieren Sie innerhalb von 10 Sekunden. Wenn Ihr Handler schwere Arbeiten ausführen muss, z. B. eine andere API aufrufen, in eine Datenbank schreiben oder einen komplexen Vorgang ausführen muss, erledigen Sie dies asynchron. Akzeptieren Sie den Webhook sofort mit einem 200 und verarbeiten Sie ihn dann in einem Hintergrundjob oder einer Warteschlange. Deduplizieren Sie mithilfe der Ereignis-ID. Speichern Sie alle von Ihnen verarbeiteten X-Cowlendar-Event-Id. Wenn Sie die gleiche ID erneut erhalten, überspringen Sie diese. Cowlendar versucht es bei einem Fehler erneut mit derselben ID. Verwenden Sie einen Konstantzeitvergleich für Signaturen. crypto.timingSafeEqual in Node.js, hmac.compare_digest in Python und hash_equals in PHP. Reguläre String-Vergleiche wie === sind anfällig für Timing-Angriffe. Versuchen Sie es nicht erneut. Cowlendar verarbeitet Wiederholungsversuche automatisch. Wenn auf Ihrem Server ein vorübergehendes Problem aufgetreten ist, geben Sie 5xx zurück, und Cowlendar wird in seinem Wiederholungsplan wiederkommen. Behandeln Sie webhook.ping explizit. Geben Sie 200 sofort für Ping-Ereignisse zurück. Dadurch können Sie die Schaltfläche „Testen“ verwenden, ohne Ihre Geschäftslogik auszulösen.

Aktuelle Einschränkungen

Über die API erstellte Buchungen sind manuelle Buchungen. Sie erstellen keine Shopify-Bestellung. Wenn Ihr Dienst normalerweise den Shopify-Checkout verwendet, wird dieser von der API umgangen. Bestätigungs-E-Mails, SMS und Kalendersynchronisierung funktionieren weiterhin normal. Noch kein Verfügbarkeitsendpunkt. Mit der aktuellen API können Sie Dienste und Buchungen lesen und Buchungen erstellen. Verfügbare Zeitfenster werden nicht angezeigt. Um zu prüfen, ob ein Zeitfenster verfügbar ist, versuchen Sie, die Buchung zu erstellen und die 422-Antwort zu verarbeiten, wenn das Zeitfenster belegt ist. Ein Verfügbarkeitsendpunkt kann in einem zukünftigen Update hinzugefügt werden. Noch keine Endpunkte aktualisieren oder löschen. Sie können Buchungen erstellen und lesen, aber Sie können sie nicht über die API aktualisieren, neu planen oder stornieren. Verwalten Sie diese Aktionen vorerst über den Cowlendar-Administrator. Es gelten Ratenbeschränkungen. Wenn Sie in einem kurzen Zeitfenster zu viele Anfragen senden, gibt die API 429 zurück. Fügen Sie für Massenvorgänge wie den Export aller Buchungen eine kurze Verzögerung zwischen paginierten Anfragen hinzu, beispielsweise 200 bis 500 ms. Webhook-Geheimnisse werden nur einmal angezeigt. Wenn Sie Ihr Signaturgeheimnis verlieren, löschen Sie den Endpunkt und erstellen Sie einen neuen, um ein neues Geheimnis zu erhalten. Webhooks erfordern HTTPS. HTTP-Endpunkte werden nicht akzeptiert.

FAQ

Kann ich die Cowlendar-API mit Zapier oder Make verwenden, ohne Code zu schreiben?

Ja. Für Webhooks, die Ereignisse von Cowlendar empfangen, erstellen Sie einen "Custom Webhook"-Trigger in Zapier oder Make, kopieren Sie die URL, die Sie erhalten, und fügen Sie sie als Endpunkt in Cowlendar Settings > Webhooks hinzu. Jedes Buchungsereignis löst Ihre Automatisierung aus. Für die API, die Anfragen an Cowlendar sendet, verwenden Sie die Aktion "HTTP Request" in Zapier oder Make, um einen beliebigen Cowlendar-API-Endpunkt mit Ihrem Bearer-Token aufzurufen.

Senden über die API erstellte Buchungen E-Mails an Kunden?

Ja. Über die API erstellte Buchungen werden genauso behandelt wie manuelle Buchungen. Bestätigungs-E-Mails, SMS-Benachrichtigungen und die Kalendersynchronisierung werden alle automatisch ausgelöst, genau wie bei einer Buchung, die über das Admin-Panel vorgenommen wird.

Was passiert, wenn mein Webhook-Endpunkt ausfällt?

Cowlendar wiederholt fehlgeschlagene Lieferungen innerhalb von ca. 3 Tagen sechsmal. Nach etwa 20 aufeinanderfolgenden Fehlern wird der Endpunkt automatisch deaktiviert und Sie erhalten eine E-Mail. Aktivieren Sie es erneut über Settings > Webhooks, sobald Ihr Server wieder verfügbar ist.

Kann ich mehrere Webhook-Endpunkte haben?

Ja. Erstellen Sie so viele, wie Sie benötigen, jeweils mit unterschiedlichen Ereignisauswahlen und URLs. Beispielsweise ein Endpunkt für Ihr CRM, der booking.created und booking.canceled überwacht, und ein anderer für Ihr analytics pipeline, der alle Ereignisse überwacht.

Kann ich ein API-Token widerrufen? Ja. Gehen Sie zu Settings > Public API und klicken Sie auf die Schaltfläche Revoke . Der Token funktioniert sofort nicht mehr. Gibt es eine Sandbox oder eine Staging-Umgebung?

Derzeit nicht. Verwenden Sie die Schaltfläche „webhook.ping Test“, um Ihr Webhook-Setup zu validieren, ohne echte Buchungen zu erstellen. Für API-Tests empfehlen wir, in Ihrem Cowlendar-Administrator einen Testdienst zu erstellen, den Sie nur für die Entwicklung verwenden.

Wo ist die vollständige API-Referenz?

Die interaktive API-Dokumentation mit allen Schemata, Parametern und Antwortbeispielen finden Sie unter https://app.cowlendar.com/public-api/docs

Cowlendar
Ready to use Cowlendar?
Open the app directly in your Shopify store.