← Zurück zum Blog

Digistore24 ohne Schnittstelle: Verkäufe per Webhook automatisieren

Wenn du digitale Produkte über Digistore24 verkaufst, wirst du schnell feststellen: eine richtige API gibt es nicht. Kein SDK, keine Bibliothek, kein OAuth-Flow. Was Digistore24 bietet, ist ein IPN — ein Digistore24 Webhook, der bei Verkauf, Refund oder Chargeback an eine URL deiner Wahl feuert. Für das Projekt Profit Prime habe ich darauf eine vollständige Fulfillment-Logik aufgebaut: Kurszugänge anlegen, Multi-Tier-Affiliate-Provisionen verwalten und Refunds mit Clawback verarbeiten. Hier ist, wie das funktioniert — und wo die Fallstricke sind.

Den Digistore24 Webhook empfangen

Digistore24 schickt einen HTTP-POST an deine Endpoint-URL, wenn ein definiertes Event eintritt. Du registrierst die URL in deinem Vendor-Account unter "IPN-Einstellungen". Die Payload kommt als application/x-www-form-urlencoded — kein JSON, was viele überrascht.

Als WordPress-Entwickler registrierst du einen Custom REST Endpoint:

add_action( 'rest_api_init', function () {
    register_rest_route( 'myplugin/v1', '/digistore-ipn', [
        'methods'             => 'POST',
        'callback'            => 'handle_digistore_ipn',
        'permission_callback' => '__return_true',
    ] );
} );

Keine WordPress-Nonce, keine Cookie-Auth — das Request kommt von Digistore24, nicht von einem Browser. __return_true ist hier korrekt, die Absicherung läuft über die Signaturprüfung.

Digistore24 signiert die Payload mit einem SHA-512-HMAC. Prüfe die Signatur als allererstes, bevor du irgendetwas anderes tust:

$secret     = get_option( 'digistore_ipn_secret' );
$body       = file_get_contents( 'php://input' );
$given_sig  = $_SERVER['HTTP_X_IPN_SIGNATURE'] ?? '';
$expected   = hash_hmac( 'sha512', $body, $secret );

if ( ! hash_equals( $expected, $given_sig ) ) {
    status_header( 403 );
    exit;
}

Ohne diese Prüfung kann jeder beliebige Request Zugänge anlegen.

Was du bei einem Verkauf tust

Das Event ipn_action = 'paid' signalisiert einen erfolgreichen Kauf. Deine Aufgaben:

  1. Käufer-E-Mail aus der Payload auslesen
  2. WordPress-User anlegen oder vorhandenen finden
  3. MasterStudy LMS: Kurs-Enrollment hinzufügen
  4. AffiliateWP: Provision für den Affiliate eintragen (mit korrektem Referral-Betrag)
  5. Transaktion in eigener Tabelle loggen

Für Multi-Tier-Affiliate musst du die Affiliate-Hierarchie selbst traversieren — AffiliateWP bietet dafür keine native Lösung out of the box. Das geht über eine rekursive Abfrage der Affiliate-Eltern-Beziehung, wobei du für jede Tier-Stufe einen eigenen Referral-Eintrag anlegst.

Idempotenz: Wie du mit Retries umgehst

Digistore24 sendet Webhooks erneut, wenn dein Endpoint nicht mit 200 antwortet — oder auch wenn es Netzwerkprobleme gibt. Du kannst denselben IPN mehrfach erhalten. Ohne Schutz dagegen legst du doppelte Accounts an, buchst Provisionen mehrfach oder gibst Zugang, der bereits existiert.

Die Lösung ist eine Idempotenz-Tabelle. Speichere order_id + ipn_action als zusammengesetzten Schlüssel und verarbeite das Event nur einmal:

$key = $order_id . '_' . $ipn_action;

if ( get_transient( 'ds_ipn_processed_' . md5( $key ) ) ) {
    wp_send_json_success( [ 'status' => 'already_processed' ] );
    exit;
}

set_transient( 'ds_ipn_processed_' . md5( $key ), true, DAY_IN_SECONDS * 30 );

Transients sind schnell, aber bei parallelen Requests auf stark frequentierten Endpoints besser mit einem Datenbank-Lock arbeiten. Für die meisten Projekte reichen Transients völlig aus.

Refunds und Chargebacks — Revoke und Clawback

Bei ipn_action = 'refund' oder 'chargeback' musst du rückabwickeln:

  • Kurszugang entziehen: MasterStudy LMS Enrollment entfernen
  • Provision rückbuchen: Bestehenden AffiliateWP-Referral auf "Rejected" setzen oder einen negativen Ausgleichs-Referral anlegen (je nachdem, ob der Affiliate bereits ausgezahlt wurde)
  • Multi-Tier-Clawback: Alle Tier-Ebenen rückabwickeln, nicht nur die erste

Für den Clawback gilt dieselbe Idempotenz-Logik. Ein Refund-Event darf den Zugang nur einmal entziehen, auch wenn Digistore24 es dreimal sendet.

Logging und warum du immer 200 zurückgibst

Log jede eingehende IPN mit Payload, Timestamp und Verarbeitungsstatus. Wenn etwas schiefgeht, willst du wissen was — und zwar nicht erst, wenn sich ein Käufer beschwert, der keinen Zugang bekommen hat.

Gib immer HTTP 200 zurück, solange die Signatur gültig ist — auch wenn die Verarbeitung intern fehlschlägt. Wenn du einen Fehler-Statuscode zurückgibst, schickt Digistore24 denselben IPN erneut, was du mit Idempotenz zwar absichern kannst, aber unnötige Retries erzeugt. Die korrekte Fehlerbehandlung ist: loggen, 200 antworten, und den Fehlerfall asynchron nachbearbeiten (z. B. über eine WordPress Queue oder einen Cron-Job).

// Am Ende des Handlers immer:
wp_send_json_success( [ 'status' => 'ok' ] );
exit;

Fazit

Kein offizielles API bedeutet nicht, dass Automatisierung unmöglich ist. Der Digistore24 IPN-Webhook ist robust genug, um darauf vollständiges Fulfillment, Refund-Handling und Affiliate-Logik aufzubauen — wenn du Signaturprüfung, Idempotenz und sauberes Logging von Anfang an einbaust. Wer das nachrüstet, macht mehr Arbeit als wer es von vorne richtig macht.

Du baust gerade ein ähnliches System oder willst die Architektur einmal durchdenken? Schreib mir — ich helfe dir dabei, die richtigen Entscheidungen früh zu treffen.