Zum Hauptinhalt springen
Getly

Befehlsmenü

Zu einer Seite springen oder den Katalog durchsuchen

Wie man Bestellungen mit dem Webhook sale.completed ausliefert

HTTPS-Endpunkt registrieren, den Header X-Getly-Signature-V2 prüfen, buyerEmail und items aus sale.completed lesen und jede Bestellung genau einmal ausliefern.

7 Min. Lesezeit
1.250 Wörter
Wie man Bestellungen mit dem Webhook sale.completed ausliefert

Manche Produkte können keine Datei in einem Download sein: ein Konto in deinem eigenen Dienst, ein Platz auf einer Kursplattform, die du betreibst, eine Lizenz, die deine eigene Software prüft. Für diese Fälle sagt Getly deinem Server in dem Moment Bescheid, in dem ein Verkauf abgeschlossen ist, und dein Server übernimmt die Auslieferung. Diese Nachricht ist der Webhook sale.completed.

Seit dem 26. September 2026 zählt er mehr als vorher. Ein kostenpflichtiges Listing, dessen einziger Inhalt das Versprechen ist, das Produkt später per E-Mail zu schicken, geht jetzt in die Prüfung statt live, es sei denn, die Auslieferung ist so automatisiert, dass Getly es nachprüfen kann: Getly-Lizenzschlüssel, dein eigener Schlüsselpool oder ein funktionierender sale.completed-Webhook. Diese Anleitung behandelt den dritten Weg von Anfang bis Ende. Gemessen am 26. September 2026 nutzen 0,11% der aktiven Listings Getly-Schlüssel und 0,10% einen eigenen Schlüsselpool; wenn du nur einen Schlüssel auslieferst, sind diese beiden einfacher als ein Server. Den Webhook brauchst du, wenn nur dein System die Auslieferung erledigen kann.

Schritt 1: Endpunkt registrieren

  1. Öffne im Dashboard Developer, dann Webhooks, und drücke Endpunkt hinzufügen.
  2. Endpunkt-URL: eine öffentliche https-Adresse auf deinem Server. Einfaches http, localhost und Adressen privater Netze werden abgelehnt.
  3. Shop: der Shop, dessen Verkäufe dieser Endpunkt empfangen soll.
  4. Ereignisse: Setze den Haken bei Verkauf abgeschlossen selbst. Es gibt auch Alle Ereignisse, aber die Prüfung, die Listings mit E-Mail-Auslieferung live gehen lässt, sucht das Abo auf sale.completed beim Namen, also wähle das Ereignis ausdrücklich.
  5. Drücke Endpunkt registrieren.

Danach erscheint ein Feld Speichere dein Signing-Secret jetzt. Das Secret wird nur dieses eine Mal angezeigt. Kopiere es in die Umgebung deines Servers (in den Beispielen unten heißt es GETLY_WEBHOOK_SECRET). Bearbeitest du den Endpunkt später, bleibt das Secret gleich; löschst du ihn und legst einen neuen an, gibt es ein neues Secret, und dein Server lehnt Zustellungen ab, bis du es aktualisierst.

Schritt 2: Wissen, was ankommt

Jede Zustellung ist ein POST mit JSON-Body und drei Headern: X-Getly-Event (der Ereignisname), X-Getly-Signature-V2 und der ältere X-Getly-Signature. Ein sale.completed-Body sieht so aus:

{
  "deliveryId": "uuid",
  "event": "sale.completed",
  "data": {
    "orderId": "uuid",
    "buyerId": "uuid",
    "buyerEmail": "[email protected]",
    "items": [
      {
        "orderItemId": "uuid",
        "productId": "uuid",
        "price": 2999,
        "sellerAmount": 2399,
        "isGift": false,
        "licenseKey": null
      }
    ],
    "total": 2999
  },
  "timestamp": "2026-10-11T09:00:00.000Z"
}

Was du wissen solltest, bevor du eine Zeile Code schreibst:

  • Beträge sind in Cent: 2999 sind $29.99.
  • Eine Zustellung umfasst deine Positionen in einer Bestellung. Liegen Produkte mehrerer Shops im Warenkorb, bekommt jeder Shop nur seine eigenen Zeilen, und total ist deren Summe.
  • items kann mehr als ein Produkt enthalten. Geh die ganze Liste durch, statt nur den ersten Eintrag zu lesen.
  • buyerEmail ist die Adresse, mit der der Käufer bezahlt hat, dieselbe, die du ohnehin bei deinen Kunden siehst. Ist isGift true, ist es trotzdem die Adresse des Schenkenden; die Adresse des Empfängers wird nicht weitergegeben, also schick die verschenkte Position an den Käufer.
  • licenseKey enthält den Schlüssel, der für diese Position ausgegeben wurde, wenn das Listing Getly-Schlüssel oder deinen Schlüsselpool nutzt, und sonst null, ebenso solange der Schlüssel darauf wartet, dass du neue Schlüssel hinzufügst.
  • Verkäufe über einen Checkout-Link tragen zusätzlich checkoutLinkId, reference und metadata, damit du die Zahlung dem zuordnen kannst, was den Link erzeugt hat.

Schritt 3: Signatur prüfen

Jeder kann einen POST an deine URL schicken. Die Signatur zeigt dir, dass dieser von Getly kommt. Der Header sieht aus wie t=1760173200,v1=5f2c...: t ist ein Unix-Zeitstempel in Sekunden, v1 ist der hex-kodierte HMAC-SHA256 der Zeichenkette aus t, einem Punkt und dem rohen Request-Body, mit deinem Signing-Secret als Schlüssel.

Zwei Details lassen die meisten ersten Versuche scheitern. Erstens: Signiert wird der rohe Body genau so, wie er ankommt. Wenn du das JSON parst und wieder serialisierst, können sich Leerzeichen oder die Reihenfolge der Schlüssel ändern, und die Signatur passt nicht mehr. Zweitens: Lehne alte Zeitstempel ab. Fünf Minuten Toleranz sind das empfohlene Fenster; es verhindert, dass jemand eine abgefangene Zustellung später erneut abspielt.

Hier ein vollständiger Handler für Node.js mit Express:

const crypto = require('crypto');
const express = require('express');

const app = express();
const SECRET = process.env.GETLY_WEBHOOK_SECRET;
const TOLERANCE_SECONDS = 300;

function verifyGetly(rawBody, header) {
  if (!header) return false;
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const t = Number(parts.t);
  if (!Number.isFinite(t) || !parts.v1) return false;
  if (Math.abs(Date.now() / 1000 - t) > TOLERANCE_SECONDS) return false;
  const expected = crypto.createHmac('sha256', SECRET).update(`${t}.${rawBody}`).digest('hex');
  const a = Buffer.from(expected, 'hex');
  const b = Buffer.from(parts.v1, 'hex');
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

// express.raw keeps the body as bytes, exactly as Getly signed it.
app.post('/getly/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const raw = req.body.toString('utf8');
  if (!verifyGetly(raw, req.get('X-Getly-Signature-V2'))) {
    return res.status(401).send('invalid signature');
  }

  const { event, data } = JSON.parse(raw);
  if (event !== 'sale.completed') return res.sendStatus(200); // includes the dashboard "test" event

  for (const item of data.items) {
    if (await alreadyDelivered(item.orderItemId)) continue;   // your database
    await deliver({                                           // your system
      email: data.buyerEmail,
      productId: item.productId,
      licenseKey: item.licenseKey,
    });
    await markDelivered(item.orderItemId);
  }

  res.sendStatus(200);
});

app.listen(3000);

alreadyDelivered, deliver und markDelivered schreibst du selbst: eine Tabelle mit orderItemId als Schlüssel und das, was auf deiner Seite das Konto anlegt oder die E-Mail verschickt.

Schritt 4: Schnell antworten und genau einmal ausliefern

Getly wartet 10 Sekunden auf eine 2xx-Antwort. Alles andere gilt als Fehlschlag: ein 4xx oder 5xx, ein Timeout und auch eine Weiterleitung, denn Zustellungen folgen keinen Redirects. Trag die endgültige URL ein, nicht eine, die weiterleitet.

Eine fehlgeschlagene Zustellung wird mit wachsenden Abständen wiederholt: nach etwa 1 Minute, dann nach 5 Minuten, 30 Minuten und 2 Stunden. Nach dem fünften Versuch wird sie als fehlgeschlagen markiert. Wegen dieser Wiederholungen stützt sich der Handler oben auf orderItemId. Hat dein Server ausgeliefert, aber zu langsam geantwortet, kommt dieselbe Bestellung noch einmal, und ohne die Prüfung bekommt der Käufer zwei Konten oder zwei E-Mails. orderItemId bleibt über alle Versuche gleich, timestamp und Signatur nicht. Dauert die Auslieferung selbst länger als ein paar Sekunden, speichere die Bestellung, antworte mit 200 und erledige die langsame Arbeit in einem Hintergrundjob.

Schritt 5: Testen, bevor du dich darauf verlässt

Drücke auf der Karte des Endpunkts Test. Getly schickt ein signiertes Ereignis namens test mit einer kurzen Nachricht in data, und die Meldung zeigt dir, ob dein Server 2xx zurückgegeben hat; wenn nicht, zitiert sie den Anfang der Serverantwort oder den Verbindungsfehler, und so siehst du am schnellsten den Grund. Logs listet die letzten Zustellungen mit Ereignis, dem Statuscode deines Servers und der Zahl der Versuche.

Testkäufe aus der Verkäufer-Sandbox senden keine Webhooks; sie bleiben von allem getrennt, was andere Systeme berührt. Signatur und Antwort testest du mit dem Test-Button, deinen Auslieferungscode mit einem echten, günstigen Listing.

Halte den Endpunkt gesund. Die Ausnahme für Listings mit E-Mail-Auslieferung geht bei nachweislich schlechter Bilanz verloren: drei oder mehr Zustellungen in 30 Tagen, von denen weniger als 90% mit 2xx beantwortet wurden. Fehlgeschlagene Test-Zustellungen auf demselben Endpunkt zählen mit, also repariere den Endpunkt, bevor du zwanzigmal auf Test drückst.

Was du heute tun kannst

Registriere einen Endpunkt mit dem Haken bei Verkauf abgeschlossen, speichere das Secret, deploye den Handler oben mit deiner eigenen deliver-Funktion und drücke Test, bis die Meldung sagt, dass die Zustellung geklappt hat. Öffne dann die Beschreibung deines Listings und schreib klar, was der Käufer bekommt und wann, zum Beispiel "ein Konto wird innerhalb einer Minute nach der Zahlung für die E-Mail angelegt, mit der du bezahlst". Die Arbeit macht der Webhook; die Beschreibung ist das, was der Käufer vor dem Bezahlen liest.

Bereit zu starten?

Unabhängiger Marktplatz für digitale Creators. Behalte 80–90 % von jedem Verkauf. Akzeptiere Karten und Stablecoins.