Dokun API-Dokumentation
Die Dokun-API dient der Anbindung deiner Kasse (POS) und eigener Systeme. Alle Anfragen nutzen JSON über HTTPS. Basis-URL:
https://dokun.io/api/v1Paketvoraussetzung
API und Webhooks sind nur im Pro-Paket verfügbar. Das Paket wird bei jeder Anfrage geprüft: Ist die Testphase abgelaufen oder die Zahlung fehlgeschlagen, antworten Anfragen mit 402, in Nicht-Pro-Paketen mit 403; Webhooks werden nicht gesendet.
Authentifizierung
Erstelle einen API-Schlüssel im Dashboard. Schlüssel beginnen mit dk_ und werden nur einmal bei der Erstellung angezeigt (wir speichern nur einen Hash). Sende ihn bei jeder Anfrage im Authorization-Header mit dem Bearer-Schema. Der Schlüssel ist an dein Unternehmen gebunden und greift nur auf eigene Karten zu.
Authorization: Bearer dk_...Ratenbegrenzung
Höchstens 60 Anfragen pro Minute und Schlüssel. Bei Überschreitung antwortet die API mit 429; der retry-after-Header nennt die Sekunden bis zur nächsten Minute.
Fehlercodes
Fehlerantworten sind Klartext, kein JSON. Werte den Statuscode aus.
| Code | Body | Wann |
|---|---|---|
| 400 | serial gerekli / geçersiz Idempotency-Key | serial fehlt oder Idempotency-Key ungültig |
| 401 | unauthorized | Schlüssel fehlt oder ungültig |
| 402 | payment required | Testphase abgelaufen oder Abo gesperrt |
| 403 | plan | Paket enthält keine API (nicht Pro) |
| 404 | kart bulunamadı | Karte nicht gefunden oder gehört einem anderen Unternehmen |
| 409 | istek işleniyor | Anfrage mit gleichem Idempotency-Key läuft noch |
| 429 | rate limit | Ratenlimit überschritten |
Kunden abrufen
GET /api/v1/customers
Liefert die Kunden deines Unternehmens, neueste zuerst. Es gibt keine Paginierung: Die Antwort enthält höchstens 200 Einträge (die 200 neuesten Anmeldungen). marketing_consent_at ist der Zeitpunkt der Werbeeinwilligung, sonst null.
curl https://dokun.io/api/v1/customers \
-H "Authorization: Bearer dk_..."
{ "customers": [ { "id": "…", "name": "Ayşe", "email": "ayse@example.com",
"created_at": "2026-10-30T09:12:00Z", "marketing_consent_at": null } ] }Stempel buchen
POST /api/v1/stamp
Bucht Stempel auf eine Karte. serial ist die Seriennummer oder der vollständige an der Kasse gescannte QR-Text (unverändert senden). delta ist optional, Standard 1. multiplier in der Antwort ist der durch eine Aktion (z. B. Doppelstempel) angewandte Faktor. Bei Erfolg wird die Karte in Apple Wallet aktualisiert und der stamp-Webhook ausgelöst.
curl -X POST https://dokun.io/api/v1/stamp \
-H "Authorization: Bearer dk_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: fis-000123" \
-d '{"serial": "ABC123", "delta": 1}'
{ "ok": true, "balance": 4, "multiplier": 1 }Idempotency-Key
Für sichere Wiederholungen nach Netzwerkfehlern sende den optionalen Header Idempotency-Key (1–64 druckbare ASCII-Zeichen, z. B. Belegnummer). Derselbe Schlüssel liefert 24 Stunden lang dieselbe Antwort, der Stempel wird nicht wiederholt; eine wiederholte Antwort trägt den Header idempotent-replayed: true. Nur erfolgreiche Antworten werden gespeichert; eine fehlgeschlagene Anfrage kann mit demselben Schlüssel wiederholt werden.
Webhooks
Lege im Dashboard einen Webhook mit HTTPS-URL und Ereignistyp an. Bei jedem Ereignis senden wir einen POST mit JSON-Body an deine URL. Format: event (Ereignisname), data (Ereignisdaten), ts (Unix-Zeit in Millisekunden).
| Ereignis | data-Felder | Wann |
|---|---|---|
| signup | email, serial | Neue Kartenanmeldung. Enthält personenbezogene Daten (E-Mail); sicher speichern. |
| stamp | serial, balance | Stempel an der Kasse oder im Dashboard |
| stamp | serial, delta, multiplier, balance | Stempel über die API |
| reward | serial, balance, target | Prämie erreicht. Nur bei Kassen-/Dashboard-Stempeln, nicht bei API-Stempeln. |
POST https://ornek.com/dokun-webhook
content-type: application/json
x-dokun-signature: 5d41402abc4b2a76…
x-dokun-attempt: 1
{ "event": "stamp", "data": { "serial": "ABC123", "balance": 4 }, "ts": 1761815520000 }Zustellung und Wiederholungen
Nur eine 2xx-Antwort gilt als Erfolg; Weiterleitungen (3xx) werden nicht verfolgt, Anfragen laufen nach etwa 5 Sekunden ab. Fehlgeschlagene Zustellungen werden mit exponentiellem Backoff (nach etwa 2 und 4 Minuten) bis zu insgesamt 3 Versuchen wiederholt; der Header x-dokun-attempt nennt die Versuchsnummer. Wiederholungen senden denselben Body: nutze event + ts + data gegen Doppelverarbeitung.
Signaturprüfung
Bei jeder Anfrage ist der Header x-dokun-signature der HMAC-SHA256 des rohen Bodys mit deinem Webhook-Secret (der im Dashboard angezeigte Wert, unverändert), hex-kodiert. Prüfe gegen den Rohtext vor dem JSON-Parsing und vergleiche in konstanter Zeit. Die Signatur enthält keinen Zeitstempel; prüfe das Feld ts gegen Replays (z. B. Ereignisse älter als 10 Minuten ablehnen).
import { createHmac, timingSafeEqual } from 'node:crypto'
const raw = await req.text() // JSON.parse'tan önce ham gövde
const expected = createHmac('sha256', process.env.DOKUN_WEBHOOK_SECRET).update(raw).digest()
const got = Buffer.from(req.headers.get('x-dokun-signature') ?? '', 'hex')
if (got.length !== expected.length || !timingSafeEqual(got, expected)) return new Response(null, { status: 401 })
const { event, data, ts } = JSON.parse(raw)
if (Date.now() - ts > 10 * 60_000) return new Response(null, { status: 400 })Fragen: WhatsApp