Skip to content

Winglark

Entwicklerreferenz

Winglark-API und Webhooks

Veranstaltungen, Gäste, Antworten und Einlässe lesen, Gäste hinzufügen und sofort erfahren, wenn etwas passiert. Eine REST-API mit JSON, Schlüsseln mit begrenzten Berechtigungen und signierten Webhooks.

API und Webhooks gehören zu den Tarifen Professional und Agency. Schlüssel und Webhooks legt der Inhaber des Arbeitsbereichs oder ein Manager unter Unternehmen → Integrationen an.

Überblick

Die Basisadresse ist https://winglark.com/api/v1. Jede Anfrage und jede Antwort ist JSON über HTTPS. Datumsangaben sind ISO-8601 in UTC, IDs sind UUIDs.

Die API ist für Server gedacht. Sie sendet keine CORS-Header und ignoriert Cookies: Rufen Sie sie aus Ihrem Backend auf, nie aus einem Browser, und halten Sie den Schlüssel aus Client-Code heraus.

Authentifizierung

Senden Sie den Schlüssel im Authorization-Header als Bearer-Token. Ein Schlüssel wird nur einmal angezeigt, bei der Erstellung; Winglark speichert nur einen verschlüsselten Hash davon.

Ein Schlüssel handelt im Namen des Mitglieds, das ihn erstellt hat, begrenzt auf seine Berechtigungen. Er wird abgelehnt, wenn er widerrufen oder abgelaufen ist, wenn dieses Mitglied den Arbeitsbereich verlassen hat oder Integrationen nicht mehr verwalten darf oder wenn der Tarif die API nicht mehr enthält.

curl https://winglark.com/api/v1/events \
  -H "Authorization: Bearer wlk_live_ab12cd34_…"

Berechtigungen

Jeder Endpunkt verlangt eine Berechtigung. Ein Schlüssel mit guests:write darf Gäste auch lesen. Kontaktdaten (E-Mail, Telefon) sind maskiert, es sei denn, der Schlüssel wurde von einem Mitglied, das sie sehen darf, mit sichtbaren Kontaktdaten erstellt.

BerechtigungBedeutung
events:readVeranstaltungen lesen. Titel, Termine, Orte und Status.
guests:readGäste lesen. Die Gästeliste jeder Veranstaltung.
guests:writeGäste hinzufügen und bearbeiten. Nach denselben Regeln wie im Panel: Tariflimit und Dublettenprüfung gelten.
rsvps:readAntworten lesen. Wer geantwortet hat, wie viele kommen. Nie Angaben zu Ernährung, Allergien oder Barrierefreiheit.
checkins:readEinlässe lesen. Wer wann durch welche Tür kam.
webhooks:manageWebhooks verwalten. Erlaubt einem Automatisierungswerkzeug, sich selbst an- und abzumelden.

Fehler

Fehler nutzen den HTTP-Status und einen JSON-Body mit einem festen code und einem Satz für Menschen. Jede Antwort trägt X-Request-Id; nennen Sie sie, wenn Sie uns schreiben.

400
Ein Parameter ist ungültig.
401
Kein Schlüssel, ein unbekannter, widerrufener oder abgelaufener Schlüssel.
403
Dem Schlüssel fehlt die Berechtigung, sein Ersteller hat den Zugriff verloren, oder der Tarif enthält die API nicht.
404
Kein solcher Datensatz in diesem Arbeitsbereich.
409
Die Anfrage widerspricht dem Datensatz: doppelte Adresse, Gästelimit des Tarifs, geschlossene Veranstaltung.
422
Felder fehlen oder sind ungültig.
429
Zu viele Anfragen; warten Sie Retry-After ab.
500
Unser Fehler. Wiederholen Sie mit demselben Idempotency-Key.
HTTP/1.1 409 Conflict
X-Request-Id: req_4f1e…

{ "error": { "code": "guest_limit_reached", "message": "This event has reached the guest limit of the workspace plan." } }

Seitenweise Abfrage

Listen beginnen mit dem Neuesten und liefern bis zu limit Einträge (Standard 50, höchstens 100). Ist has_more true, übergeben Sie next_cursor als cursor für die nächste Seite. Gäste- und Antwortlisten akzeptieren außerdem updated_since als ISO-Datum.

Ratenlimits

600 Anfragen pro Minute je Schlüssel und 1.200 je Netzwerk. Darüber lautet die Antwort 429 mit Retry-After in Sekunden. Wiederholte Anfragen mit ungültigem Schlüssel werden zehn Minuten lang abgelehnt.

Idempotenz

Senden Sie bei einer Erstellung den Header Idempotency-Key. 24 Stunden lang liefert eine Wiederholung mit demselben Schlüssel und demselben Body die erste Antwort (markiert mit Idempotent-Replayed), statt einen zweiten Gast anzulegen. Derselbe Schlüssel mit anderem Body wird mit 422 abgelehnt.

curl -X POST https://winglark.com/api/v1/events/{event_id}/guests \
  -H "Authorization: Bearer wlk_live_ab12cd34_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: crm-10442-create" \
  -d '{ "first_name": "Ada", "email": "ada@example.com" }'

Endpunkte

Jeder Listen-Endpunkt akzeptiert limit und cursor.

GET/v1/me

Der Schlüssel selbst: seine Berechtigungen und sein Arbeitsbereich. Zum Testen eines Schlüssels.

Berechtigung: —

{
  "object": "api_key",
  "id": "3b2a1c0d-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
  "name": "CRM sync",
  "prefix": "wlk_live_ab12cd34",
  "scopes": ["events:read", "guests:read", "rsvps:read"],
  "contacts_visible": false,
  "created_at": "2026-11-04T10:00:00.000Z",
  "expires_at": null,
  "organization": { "id": "9d8c7b6a-5f4e-4d3c-a2b1-0f9e8d7c6b5a", "name": "Northwind Events" }
}

GET/v1/events

Die Veranstaltungen des Arbeitsbereichs, neueste zuerst. Filter mit status.

Berechtigung: events:read · ?status=active&limit=20

{
  "object": "list",
  "data": [
    {
      "id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
      "object": "event",
      "title": "Spring partner summit",
      "summary": "",
      "status": "active",
      "type": "corporate",
      "starts_at": "2026-12-03T09:00:00.000Z",
      "ends_at": "2026-12-03T17:00:00.000Z",
      "timezone": "Europe/Berlin",
      "locale": "en",
      "location_mode": "in_person",
      "venue_name": "Hall 4",
      "venue_address": "Messedamm 22, Berlin",
      "rsvp_deadline": "2026-11-26T23:00:00.000Z",
      "created_at": "2026-10-20T08:12:44.120Z",
      "updated_at": "2026-11-02T15:03:10.004Z"
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMS0wNFQxMDoyMTowMy41NTFafGI4ZTFkM2M0LTlmMjAtNGE3Yi04YzYxLTVkMmUwZjlhM2IxNw"
}

GET/v1/events/{event_id}

Eine Veranstaltung.

Berechtigung: events:read

{
  "id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
  "object": "event",
  "title": "Spring partner summit",
  "summary": "",
  "status": "active",
  "type": "corporate",
  "starts_at": "2026-12-03T09:00:00.000Z",
  "ends_at": "2026-12-03T17:00:00.000Z",
  "timezone": "Europe/Berlin",
  "locale": "en",
  "location_mode": "in_person",
  "venue_name": "Hall 4",
  "venue_address": "Messedamm 22, Berlin",
  "rsvp_deadline": "2026-11-26T23:00:00.000Z",
  "created_at": "2026-10-20T08:12:44.120Z",
  "updated_at": "2026-11-02T15:03:10.004Z"
}

GET/v1/events/{event_id}/guests

Die Gäste einer Veranstaltung. include_archived=true nimmt von der Liste genommene Gäste hinzu.

Berechtigung: guests:read · ?updated_since=2026-11-01T00:00:00Z

{
  "object": "list",
  "data": [
    {
      "id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
      "object": "guest",
      "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
      "first_name": "Ada",
      "last_name": "Kaya",
      "display_name": "Ada Kaya",
      "email": "a•••@example.com",
      "phone": "••• ••• 321",
      "company": "Northwind",
      "job_title": "Head of Partnerships",
      "locale": "en",
      "guest_type": "standard",
      "status": "pending",
      "source": "api",
      "tags": ["partner"],
      "external_reference": "crm-10442",
      "expected_party_size": 1,
      "archived_at": null,
      "created_at": "2026-11-04T10:21:03.551Z",
      "updated_at": "2026-11-04T10:21:03.551Z"
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMS0wNFQxMDoyMTowMy41NTFafGI4ZTFkM2M0LTlmMjAtNGE3Yi04YzYxLTVkMmUwZjlhM2IxNw"
}

GET/v1/events/{event_id}/guests/{guest_id}

Ein Gast.

Berechtigung: guests:read

{
  "id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
  "object": "guest",
  "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
  "first_name": "Ada",
  "last_name": "Kaya",
  "display_name": "Ada Kaya",
  "email": "a•••@example.com",
  "phone": "••• ••• 321",
  "company": "Northwind",
  "job_title": "Head of Partnerships",
  "locale": "en",
  "guest_type": "standard",
  "status": "pending",
  "source": "api",
  "tags": ["partner"],
  "external_reference": "crm-10442",
  "expected_party_size": 1,
  "archived_at": null,
  "created_at": "2026-11-04T10:21:03.551Z",
  "updated_at": "2026-11-04T10:21:03.551Z"
}

POST/v1/events/{event_id}/guests

Einen Gast hinzufügen. Nur first_name ist Pflicht. Tariflimits und die Regel für doppelte Adressen gelten.

Berechtigung: guests:write

{
  "first_name": "Ada",
  "last_name": "Kaya",
  "email": "ada@example.com",
  "company": "Northwind",
  "tags": ["partner"],
  "external_reference": "crm-10442"
}
{
  "id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
  "object": "guest",
  "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
  "first_name": "Ada",
  "last_name": "Kaya",
  "display_name": "Ada Kaya",
  "email": "a•••@example.com",
  "phone": "••• ••• 321",
  "company": "Northwind",
  "job_title": "Head of Partnerships",
  "locale": "en",
  "guest_type": "standard",
  "status": "pending",
  "source": "api",
  "tags": ["partner"],
  "external_reference": "crm-10442",
  "expected_party_size": 1,
  "archived_at": null,
  "created_at": "2026-11-04T10:21:03.551Z",
  "updated_at": "2026-11-04T10:21:03.551Z"
}

PATCH/v1/events/{event_id}/guests/{guest_id}

Name, Kontaktdaten, Firma, Position, Sprache, Typ oder Schlagwörter eines Gastes ändern.

Berechtigung: guests:write

{ "job_title": "Chief Partnerships Officer", "tags": ["partner", "vip-desk"] }
{
  "id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
  "object": "guest",
  "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
  "first_name": "Ada",
  "last_name": "Kaya",
  "display_name": "Ada Kaya",
  "email": "a•••@example.com",
  "phone": "••• ••• 321",
  "company": "Northwind",
  "job_title": "Head of Partnerships",
  "locale": "en",
  "guest_type": "standard",
  "status": "pending",
  "source": "api",
  "tags": ["partner"],
  "external_reference": "crm-10442",
  "expected_party_size": 1,
  "archived_at": null,
  "created_at": "2026-11-04T10:21:03.551Z",
  "updated_at": "2026-11-04T10:21:03.551Z"
}

GET/v1/events/{event_id}/rsvps

Die Antworten zu einer Veranstaltung, zuletzt geänderte zuerst. Filter mit response.

Berechtigung: rsvps:read · ?response=yes

{
  "object": "list",
  "data": [
    {
      "id": "0c9b7a5e-3d1f-4e2a-b6c8-9f0e1d2c3b4a",
      "object": "rsvp",
      "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
      "guest_id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
      "response": "yes",
      "party_size": 2,
      "attendance_mode": "in_person",
      "revision": 1,
      "responded_via": "link",
      "responded_at": "2026-11-05T18:40:12.000Z",
      "updated_at": "2026-11-05T18:40:12.000Z"
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMS0wNFQxMDoyMTowMy41NTFafGI4ZTFkM2M0LTlmMjAtNGE3Yi04YzYxLTVkMmUwZjlhM2IxNw"
}

GET/v1/events/{event_id}/checkins

Die Türprotokolle einer Veranstaltung, neueste zuerst.

Berechtigung: checkins:read

{
  "object": "list",
  "data": [
    {
      "id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
      "object": "checkin",
      "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
      "guest_id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
      "action": "admitted",
      "result": "ok",
      "admitted": 2,
      "occurred_at": "2026-12-03T08:57:31.000Z",
      "recorded_offline": false
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0xMS0wNFQxMDoyMTowMy41NTFafGI4ZTFkM2M0LTlmMjAtNGE3Yi04YzYxLTVkMmUwZjlhM2IxNw"
}

GET/v1/webhooks

Die Webhook-Endpunkte des Arbeitsbereichs.

Berechtigung: webhooks:manage

{ "object": "list", "data": [{
    "id": "e2d4c6b8-a0f1-4e3d-9c5b-7a8f6e4d2c1b",
    "object": "webhook_endpoint",
    "url": "https://hooks.example.com/winglark",
    "description": "CRM sync",
    "events": ["rsvp.submitted", "checkin.admitted"],
    "event_ids": [],
    "include_contacts": false,
    "active": true,
    "disabled_reason": null,
    "source": "api",
    "created_at": "2026-11-04T10:30:00.000Z"
  }], "has_more": false, "next_cursor": null }

POST/v1/webhooks

Eine Adresse anmelden. Die Antwort enthält das Signaturgeheimnis, einmalig.

Berechtigung: webhooks:manage

{
  "url": "https://hooks.example.com/winglark",
  "events": ["rsvp.submitted", "checkin.admitted"],
  "event_ids": [],
  "description": "CRM sync"
}
{
  "id": "e2d4c6b8-a0f1-4e3d-9c5b-7a8f6e4d2c1b",
  "object": "webhook_endpoint",
  "url": "https://hooks.example.com/winglark",
  "description": "CRM sync",
  "events": ["rsvp.submitted", "checkin.admitted"],
  "event_ids": [],
  "include_contacts": false,
  "active": true,
  "disabled_reason": null,
  "source": "api",
  "created_at": "2026-11-04T10:30:00.000Z",
  "secret": "whsec_6Jx…shown once…"
}

DELETE/v1/webhooks/{webhook_id}

Abmelden.

Berechtigung: webhooks:manage

204 No Content

Webhooks

Legen Sie einen Endpunkt im Panel oder per POST /v1/webhooks an, wählen Sie seine Ereignistypen und beschränken Sie ihn auf Wunsch auf einzelne Veranstaltungen. Winglark sendet dann pro Ereignis eine JSON-Nachricht.

Antworten Sie innerhalb von 10 Sekunden mit einem beliebigen 2xx. Weiterleitungen werden nicht verfolgt. Die id der Nachricht ist bei jeder Wiederholung und für jeden Endpunkt gleich: Nutzen Sie sie, um bereits verarbeitete Nachrichten zu ignorieren.

EreignistypWann
guest.createdEin Gast wurde hinzugefügt: von Hand, per Import, über die API oder an der Tür.
guest.updatedDie Angaben eines Gastes haben sich geändert.
guest.archivedEin Gast wurde von der Liste genommen.
rsvp.submittedEin Gast hat geantwortet oder seine Antwort geändert.
invitation.sentEine Einladungs-E-Mail wurde an den Mailanbieter übergeben.
invitation.deliveredDer Mailserver des Empfängers hat die Einladung angenommen.
invitation.bouncedDie Einladung konnte nicht zugestellt werden.
checkin.admittedJemand wurde an der Tür oder an einem Kiosk eingelassen.
ticket.issuedFür eine bezahlte Bestellung wurden Tickets ausgestellt.
event.publishedEine Veranstaltung ist live: Gäste haben ihre Links, die Tür zählt.
event.cancelledEine Veranstaltung wurde abgesagt.
seatmap.publishedEin Sitzplan wurde für die Gäste veröffentlicht.
badge.printedNamensschilder wurden gedruckt.

Die Nachricht

Jede Nachricht hat denselben Umschlag. data enthält den betreffenden Datensatz in derselben Form, die die API liefert. Nachrichten enthalten nie Einladungslinks, Ticketcodes, die private Notiz zum Gast oder Angaben zu Ernährung, Allergien und Barrierefreiheit.

Winglark-Signature
t=1762338012,v1=5f2b…c9e1
Winglark-Event
rsvp.submitted
Winglark-Delivery
7c1e9a42-…
User-Agent
Winglark-Webhooks/1
Content-Type
application/json
{
  "id": "evt_3f9a1c7e5b2d4a6c8e0f1a2b",
  "object": "event",
  "type": "rsvp.submitted",
  "api_version": "v1",
  "created_at": "2026-11-05T18:40:12.481Z",
  "organization_id": "9d8c7b6a-5f4e-4d3c-a2b1-0f9e8d7c6b5a",
  "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
  "data": {
    "rsvp": {
      "id": "0c9b7a5e-3d1f-4e2a-b6c8-9f0e1d2c3b4a",
      "object": "rsvp",
      "event_id": "6f1c2a7e-4b1d-4c55-9a3e-2f8d7b0c1e42",
      "guest_id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17",
      "response": "yes",
      "party_size": 2,
      "attendance_mode": "in_person",
      "revision": 1,
      "responded_via": "link",
      "responded_at": "2026-11-05T18:40:12.000Z",
      "updated_at": "2026-11-05T18:40:12.000Z"
    },
    "guest": { "id": "b8e1d3c4-9f20-4a7b-8c61-5d2e0f9a3b17", "first_name": "Ada", "last_name": "Kaya", "email": "a•••@example.com", "…": "…" },
    "response": "yes",
    "party_size": 2,
    "revision": 1,
    "revised": false,
    "via": "link"
  }
}

Die Signatur prüfen

Jede Nachricht trägt einen Header Winglark-Signature: t ist die Unix-Zeit der Signatur, v1 der hexadezimale HMAC-SHA256 aus t, einem Punkt und dem Roh-Body, mit dem Geheimnis Ihres Endpunkts als Schlüssel.

Berechnen Sie ihn über die Rohbytes, bevor Sie das JSON parsen, vergleichen Sie in konstanter Zeit und lehnen Sie ein t ab, das mehr als fünf Minuten von Ihrer Uhr abweicht. Nach einer Erneuerung gibt es 24 Stunden lang zwei v1-Werte; nehmen Sie die Nachricht an, wenn einer passt.

Node.js

import { createHmac, timingSafeEqual } from 'node:crypto';
import express from 'express';

const secret = process.env.WINGLARK_WEBHOOK_SECRET; // whsec_…
const app = express();

// The raw body: the signature covers the bytes, not the parsed JSON.
app.post('/winglark', express.raw({ type: 'application/json' }), (req, res) => {
  const header = req.get('Winglark-Signature') ?? '';
  const parts = header.split(',').map((part) => part.split('='));
  const t = Number(parts.find(([key]) => key === 't')?.[1]);
  const signatures = parts.filter(([key]) => key === 'v1').map(([, value]) => value);

  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return res.sendStatus(400);

  const expected = createHmac('sha256', secret).update(`${t}.`).update(req.body).digest();
  const valid = signatures.some((signature) => {
    const given = Buffer.from(signature, 'hex');
    return given.length === expected.length && timingSafeEqual(given, expected);
  });
  if (!valid) return res.sendStatus(400);

  const event = JSON.parse(req.body.toString('utf8'));
  // Deduplicate on event.id: a message can arrive more than once.
  res.sendStatus(204);
});

app.listen(3000);

Python

import hashlib
import hmac
import json
import os
import time

from flask import Flask, abort, request

SECRET = os.environ["WINGLARK_WEBHOOK_SECRET"].encode()  # whsec_…
app = Flask(__name__)


@app.post("/winglark")
def winglark():
    header = request.headers.get("Winglark-Signature", "")
    parts = [part.split("=", 1) for part in header.split(",") if "=" in part]
    t = next((value for key, value in parts if key == "t"), None)
    signatures = [value for key, value in parts if key == "v1"]

    if not t or not t.isdigit() or abs(time.time() - int(t)) > 300:
        abort(400)

    raw = request.get_data()  # the raw bytes, before any JSON parsing
    expected = hmac.new(SECRET, t.encode() + b"." + raw, hashlib.sha256).hexdigest()
    if not any(hmac.compare_digest(expected, signature) for signature in signatures):
        abort(400)

    event = json.loads(raw)
    # Deduplicate on event["id"]: a message can arrive more than once.
    return "", 204

Wiederholungen

Eine Zustellung ohne 2xx wird nach 1 Minute, 5 Minuten, 30 Minuten, 2 Stunden, 6 Stunden, 12 Stunden und 24 Stunden erneut versucht und danach als fehlgeschlagen markiert. Wiederholungen gehen bei der ersten Gelegenheit nach ihrer Fälligkeit hinaus, spätestens innerhalb einer Stunde.

Scheitert drei Tage lang jede Zustellung an einen Endpunkt, stellt Winglark das Senden ein und zeigt das im Panel an. Setzen Sie ihn fort, sobald der Empfänger behoben ist; eine fehlgeschlagene Zustellung lässt sich aus dem Protokoll erneut senden.

  1. 1. 1 min
  2. 2. 5 min
  3. 3. 30 min
  4. 4. 2 h
  5. 5. 6 h
  6. 6. 12 h
  7. 7. 24 h

Versionen

Dies ist Version 1. Innerhalb dieser Version fügen wir nur hinzu: neue Felder, neue Ereignistypen, neue optionale Parameter. Ignorieren Sie Felder, die Sie nicht kennen. Alles, was eine Integration brechen würde, kommt in eine neue, vorab angekündigte Version.

Automatisierungsplattformen

Werkzeuge mit REST-Hook-Unterstützung melden sich mit POST /v1/webhooks an und mit DELETE /v1/webhooks/{id} ab, mit einem Schlüssel mit webhooks:manage. GET /v1/me prüft einen Schlüssel. Die Listen-Endpunkte, neueste zuerst, dienen zugleich als Beispieldaten.