Dokumentation
API für Agenten
Als Text für KI-AgentenAnmeldung, Grenzen, Idempotenz, Fehler und fertige Beispiele für die öffentliche API.
Die öffentliche API liegt unter /api/v1 und richtet sich an Agenten, Skripte und eigene Anwendungen. Diese Seite fasst den Einstieg zusammen und zeigt drei vollständige Beispiele. Die verbindliche Beschreibung steht als OpenAPI 3.1 unter https://api.eventwerk.eu/openapi.json und unter /api/v1/openapi.json.
Anmeldung
Jede Anfrage trägt den API-Schlüssel im Kopf Authorization. Das Format ist Bearer ew_....
Authorization: Bearer ew_...Ein Schlüssel gehört zu genau einer Organisation und handelt mit den Rechten des Eigentümers. Als Eigentümer legen Sie ihn in den Einstellungen unter /dashboard/einstellungen an. Der volle Schlüssel wird nur einmal angezeigt.
- API-Zugang gibt es nur mit Eventwerk Plus.
- Je Organisation sind höchstens 25 aktive Schlüssel erlaubt.
- Höchstens 10 neue Schlüssel pro Tag, gezählt in einem rollierenden Zeitfenster von 24 Stunden.
- Ein zurückgezogener Schlüssel wird sofort abgelehnt und ergibt
invalid_api_key.
Der Schlüssel ist ein Geheimnis. Speichern Sie ihn nicht in Repositorys, Protokollen oder öffentlichen Konfigurationen.
Grenzen
Je Schlüssel sind 200 Anfragen pro Minute erlaubt. Der Zähler liegt im Arbeitsspeicher jeder Instanz und wird nicht über Instanzen geteilt. Bei Überschreitung antwortet die API mit Status 429, dem Code rate_limited und dem Kopf Retry-After in Sekunden. Warten Sie die genannte Zeit ab, bevor Sie es erneut versuchen.
Schreibende Aufrufe wiederholen
POST /events akzeptiert den optionalen Kopf Idempotency-Key. Damit lässt sich eine Anfrage nach einer Zeitüberschreitung wiederholen, ohne ein zweites Event anzulegen. Der Kopf darf höchstens 255 Zeichen lang sein.
- Gleicher Schlüssel und gleicher Rumpf: Die API liefert dieselbe Antwort erneut.
- Gleicher Schlüssel und anderer Rumpf: Status 409 und
idempotency_conflict. - Ohne Kopf legt jeder Aufruf ein neues Event an.
- Verwenden Sie je beabsichtigter Anlage einen eigenen, zufälligen Schlüssel.
Fehlerformat
Fehler kommen immer als JSON mit code und message. code ist stabil und für Programme gedacht. message ist eine deutsche Meldung für Menschen. Das optionale Feld details enthält zusätzliche Angaben.
{
"code": "idempotency_conflict",
"message": "Der Idempotency-Key wurde bereits mit einem anderen Rumpf verwendet."
}| Code | Status | Bedeutung |
|---|---|---|
| invalid_json | 400 | Der Rumpf ist kein gültiges JSON. |
| unknown_field | 400 | Ein Feld im Rumpf ist unbekannt. details.field nennt den Namen. |
| invalid_filter | 400 | Ein Filterwert ist unbekannt. |
| invalid_limit | 400 | Ein limit ist ungültig, etwa keine ganze Zahl oder kleiner als 1. |
| invalid_api_key | 401 | Der Schlüssel fehlt, ist unbekannt oder wurde zurückgezogen. |
| plan_required | 403 | Die Aktion erfordert Eventwerk Plus. |
| event_not_found | 404 | Das Event wurde nicht gefunden. |
| registration_not_found | 404 | Die Anmeldung wurde nicht gefunden. |
| checkin_not_found | 404 | Der QR-Token ist unbekannt. |
| idempotency_conflict | 409 | Derselbe Idempotency-Key wurde mit einem anderen Rumpf verwendet. |
| event_has_registrations | 409 | Ein veröffentlichtes Event mit Anmeldungen lässt sich nicht löschen. |
| registration_not_confirmed, registration_not_checkinable | 409 | Die Anmeldung lässt sich nicht einchecken. |
| rate_limited | 429 | Mehr als 200 Anfragen pro Minute je Schlüssel und Instanz. |
| internal_error | 500 | Interner Fehler. |
Prüfen Sie code und den HTTP-Status, nicht den deutschen Text von message.
Webhooks
Webhooks gehören zu Eventwerk Plus. Eventwerk sendet bei einer neuen Benachrichtigung einen POST mit JSON-Rumpf an die hinterlegte URL. Die Verwaltung läuft über die Sitzungs-API unter /api/webhooks, nicht über den API-Schlüssel. Die vollständige Beschreibung steht unter API: Webhooks.
- Signatur: Der Kopf
X-Eventwerk-Signatureenthältsha256=<HMAC-SHA256>über den unveränderten Rumpf, berechnet mit dem Webhook-Geheimnis. Vergleichen Sie die Signatur in konstanter Zeit. - Wiederholungen: Jeder Webhook erhält höchstens zwei Versuche im Abstand von 500 Millisekunden. Ein Versuch hat ein Zeitlimit von 5 Sekunden. Eine Antwort mit Status 2xx gilt als erfolgreich.
- Reihenfolge: Die Zustellungen sind nicht in einer festen Reihenfolge garantiert. Es gibt keine dauerhafte Warteschlange; nach einem Neustart gehen nicht zugestellte Aufrufe verloren.
Fehler bei der Zustellung werden nur protokolliert. Der auslösende Vorgang, etwa eine Anmeldung, bleibt gültig.
Verweise
- OpenAPI 3.1: https://api.eventwerk.eu/openapi.json und
/api/v1/openapi.json. - Kurze Fassung für Agenten: llms.txt.
- Alle Seiten als Markdown: llms-full.txt.
- API-Überblick im Web: API-Referenz.
Beispiele
Die Beispiele lesen den Schlüssel aus EVENTWERK_API_KEY. EVENT_ID ist die Kennung des Events, QR_TOKEN der Token aus dem Ticket. Die Basisadresse ist https://api.eventwerk.eu/api/v1. Alle Zeitpunkte in Antworten sind UTC und enden auf Z; die Zeitzone des Events steht getrennt in timezone.
Der QR-Token steht nicht in der Anmeldeliste. Er steckt im Ticket des Gasts unter /ticket/<token>.
Events auflisten
GET /events liefert eine Seite mit items, has_more und next_cursor. Jeder Eintrag enthält unter anderem id, title, start_at, timezone, status und registration_count. limit hat den Standard 50. Werte über 200 werden auf 200 begrenzt.
curl -s "https://api.eventwerk.eu/api/v1/events?limit=50" \
-H "Authorization: Bearer $EVENTWERK_API_KEY"const apiBase = "https://api.eventwerk.eu/api/v1";
const apiKey = process.env.EVENTWERK_API_KEY;
async function main() {
const response = await fetch(apiBase + "/events?limit=50", {
headers: { Authorization: "Bearer " + apiKey },
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.code + ": " + error.message);
}
const page = await response.json();
for (const event of page.items) {
console.log(event.id, event.title, event.start_at);
}
}
main();import os
import requests
api_base = "https://api.eventwerk.eu/api/v1"
api_key = os.environ["EVENTWERK_API_KEY"]
response = requests.get(
f"{api_base}/events",
params={"limit": 50},
headers={"Authorization": f"Bearer {api_key}"},
timeout=30,
)
response.raise_for_status()
page = response.json()
for event in page["items"]:
print(event["id"], event["title"], event["start_at"])Die Antwort hat die Form { "items": [...], "has_more": false, "next_cursor": null }. Ist has_more false, ist next_cursor null.
Anmeldungen eines Events lesen
GET /events/{eventID}/registrations liefert eine Seite mit items, has_more und next_cursor. Jeder Eintrag enthält unter anderem id, name, email, status, ticket_type_id, price_paid_cents, checked_in_at und created_at.
curl -s "https://api.eventwerk.eu/api/v1/events/$EVENT_ID/registrations?status=confirmed&limit=100" \
-H "Authorization: Bearer $EVENTWERK_API_KEY"const apiBase = "https://api.eventwerk.eu/api/v1";
const apiKey = process.env.EVENTWERK_API_KEY;
const eventId = process.env.EVENT_ID;
async function main() {
const url =
apiBase +
"/events/" +
encodeURIComponent(eventId) +
"/registrations?status=confirmed&limit=100";
const response = await fetch(url, {
headers: { Authorization: "Bearer " + apiKey },
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.code + ": " + error.message);
}
const page = await response.json();
for (const registration of page.items) {
console.log(
registration.id,
registration.name,
registration.status,
registration.checked_in_at,
);
}
}
main();import os
import requests
api_base = "https://api.eventwerk.eu/api/v1"
api_key = os.environ["EVENTWERK_API_KEY"]
event_id = os.environ["EVENT_ID"]
response = requests.get(
f"{api_base}/events/{event_id}/registrations",
params={"status": "confirmed", "limit": 100},
headers={"Authorization": f"Bearer {api_key}"},
timeout=30,
)
response.raise_for_status()
page = response.json()
for registration in page["items"]:
print(
registration["id"],
registration["name"],
registration["status"],
registration["checked_in_at"],
)status filtert nach pending, confirmed, waitlisted, cancelled oder declined. q sucht in Name und E-Mail-Adresse. limit hat den Standard 50. Werte über 200 werden auf 200 begrenzt.
Check-in setzen
POST /events/{eventID}/checkin setzt den Check-in einmalig. Der Rumpf enthält qr_token.
curl -s -X POST "https://api.eventwerk.eu/api/v1/events/$EVENT_ID/checkin" \
-H "Authorization: Bearer $EVENTWERK_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"qr_token\":\"$QR_TOKEN\"}"const apiBase = "https://api.eventwerk.eu/api/v1";
const apiKey = process.env.EVENTWERK_API_KEY;
const eventId = process.env.EVENT_ID;
const qrToken = process.env.QR_TOKEN;
async function main() {
const response = await fetch(
apiBase + "/events/" + encodeURIComponent(eventId) + "/checkin",
{
method: "POST",
headers: {
Authorization: "Bearer " + apiKey,
"Content-Type": "application/json",
},
body: JSON.stringify({ qr_token: qrToken }),
},
);
const result = await response.json();
if (!response.ok) {
throw new Error(result.code + ": " + result.message);
}
console.log(result.status, result.already_checked_in, result.registration.id);
}
main();import os
import requests
api_base = "https://api.eventwerk.eu/api/v1"
api_key = os.environ["EVENTWERK_API_KEY"]
event_id = os.environ["EVENT_ID"]
qr_token = os.environ["QR_TOKEN"]
response = requests.post(
f"{api_base}/events/{event_id}/checkin",
headers={"Authorization": f"Bearer {api_key}"},
json={"qr_token": qr_token},
timeout=30,
)
response.raise_for_status()
result = response.json()
print(result["status"], result["already_checked_in"], result["registration"]["id"])Die Antwort enthält status, already_checked_in und registration. Der erste Aufruf liefert checked_in und already_checked_in: false. Ein erneuter Aufruf mit demselben Token liefert already_checked_in: true und verändert den Zeitpunkt nicht. Ein unbekannter Token ergibt 404 checkin_not_found. Eine Anmeldung, die nicht eingecheckt werden kann, ergibt 409 mit registration_not_confirmed oder registration_not_checkinable.
Der Check-in ist von sich aus wiederholbar. Ein zweiter Aufruf mit demselben Token legt keinen zweiten Check-in an, sondern meldet already_checked_in.