Zum Inhalt

Payment Endpoint

Der Payment Endpoint ist eine Server-zu-Server Webhook-URL, die in Ihrem SecPaid-Konto konfiguriert wird. Wenn einer Ihrer Payment Links bezahlt wird, sendet SecPaid eine POST-Anfrage an diese URL mit den Zahlungsdetails.

Unterschied zur callback_url

Aspekt payment_endpoint callback_url
Typ Server-zu-Server HTTP POST Browser-Redirect (HTTP 302)
Zuverlässigkeit Hoch — unabhängig vom Kunden-Browser Niedrig — Kunde kann Tab schließen
Konfiguration Einmalig, kontoweit Pro Link (oder Konto-Standard)
Payload JSON-Body mit Zahlungsdetails Query-Parameter in URL
Sicherheit Kann verschlüsselt werden (AES) Leicht manipulierbar durch Endnutzer
Auslösung bei Abbruch Nein Ja (mit status=cancel)
Verwenden für Auftragsabwicklung, Backend-Logik Kundenorientiertes UI-Feedback

Konfiguration

Payment Endpoint setzen

  1. Melden Sie sich in Ihrem SecPaid-Konto an
  2. Navigieren Sie zu SettingsAPI & Integrations
  3. Geben Sie Ihre Webhook-URL im Feld Payment Endpoint ein
  4. Klicken Sie auf Save Settings
Payment Endpoint: https://ihrserver.de/api/secpaid/webhook

Dies ist Ihr Account-Standard — alle Payment Links die Sie erstellen verwenden diesen Endpoint, außer er wird pro Link via API überschrieben.

Anforderungen

Ihre Endpoint-URL muss:

  • Öffentlich erreichbar von SecPaids Servern sein
  • POST-Anfragen mit JSON-Body akzeptieren
  • Eine HTTP 2xx-Antwort zurückgeben
  • In Produktion HTTPS verwenden

Request-Details

HTTP-Anfrage

POST /api/secpaid/webhook HTTP/1.1
Host: ihrserver.de
Content-Type: application/json
Accept: application/json

{
  "ResponseCode": 1,
  "data": {
    "pay_id": 12345,
    "note": "Rechnung #1234",
    "amount": 49.99,
    "user_id": "usr-abc-def-123",
    "status": "Success"
  }
}

Payload-Felder

Feld Typ Immer vorhanden Beschreibung
ResponseCode integer Ja Immer 1
data.pay_id integer Ja Die linktopay_id die die Zahlung identifiziert
data.note string Ja Die bei Link-Erstellung gesetzte recipient_note (kann leer sein)
data.amount number Ja Vom Kunden bezahlter Betrag
data.user_id string Ja Ihre interne User-ID (der Händler der den Link erstellt hat)
data.status string Ja Immer "Success" (Endpoint feuert nur bei erfolgreicher Zahlung)

Bei Split Links wird der Payment Endpoint für jeden Empfänger im Split aufgerufen. Der konfigurierte payment_endpoint jedes Empfängers erhält den Webhook mit:

  • pay_id — gleich für alle Empfänger (die Link-ID)
  • amount — der Anteil des Empfängers, nicht der Gesamtbetrag
  • user_id — die User-ID des Empfängers
  • note — die recipient_note vom Link

Verschlüsselung

Wenn Ihr Konto Verschlüsselung aktiviert hat (is_encryption = Yes in SecPaid-Attributen), wird das Webhook-Payload vor dem Senden verschlüsselt:

Verschlüsselte Anfrage

POST /api/secpaid/webhook HTTP/1.1
Host: ihrserver.de
Content-Type: application/json

{
  "data": "U2FsdGVkX1+0Hk8Q7z...base64_verschluesselter_string..."
}

Das gesamte {ResponseCode, data: {...}}-Objekt wird:

  1. JSON-kodiert
  2. Mit AES-256-CBC unter Verwendung Ihres EncryptionKey verschlüsselt
  3. Base64-kodiert
  4. Als data-Feldwert gesendet

Siehe Verschlüsselung für Entschlüsselungsanweisungen.

Auslöse-Bedingungen

Ereignis payment_endpoint aufgerufen? callback_url aufgerufen?
Kunde bezahlt via Karte oder Banküberweisung ✅ Ja ✅ Ja (Redirect)
Admin bestätigt Banküberweisung ✅ Ja ❌ Nein (keine Browser-Session)
Kunde bricht Link ab ❌ Nein ✅ Ja (status=cancel)
Link per API gelöscht ❌ Nein ❌ Nein
Erstattung verarbeitet ❌ Nein ❌ Nein

Implementierungs-Beispiele

Route::post('/api/secpaid/webhook', function (Request $request) {
    $payload = $request->all();

    // Bei aktivierter Verschlüsselung zuerst entschlüsseln
    if (isset($payload['data']) && is_string($payload['data'])) {
        $decrypted = openssl_decrypt(
            $payload['data'],
            'AES-256-CBC',
            env('SECPAID_ENCRYPTION_KEY'),
            0,
            substr(env('SECPAID_ENCRYPTION_KEY'), 0, 16)
        );
        $payload = json_decode($decrypted, true);
    }

    $payId = $payload['data']['pay_id'];
    $amount = $payload['data']['amount'];
    $status = $payload['data']['status'];

    // Zahlung verarbeiten
    $order = Order::where('payment_link_id', $payId)->first();
    if ($order && $status === 'Success') {
        $order->update(['status' => 'paid', 'paid_amount' => $amount]);
    }

    return response()->json(['received' => true], 200);
});
app.post('/api/secpaid/webhook', (req, res) => {
  let payload = req.body;

  // Bei aktivierter Verschlüsselung zuerst entschlüsseln
  if (typeof payload.data === 'string') {
    const crypto = require('crypto');
    const key = process.env.SECPAID_ENCRYPTION_KEY;
    const iv = key.substring(0, 16);
    const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
    let decrypted = decipher.update(payload.data, 'base64', 'utf8');
    decrypted += decipher.final('utf8');
    payload = JSON.parse(decrypted);
  }

  const { pay_id, amount, status } = payload.data;

  if (status === 'Success') {
    fulfillOrder(pay_id, amount);
  }

  res.status(200).json({ received: true });
});

Webhooks testen

Entwicklungsumgebung

Verwenden Sie die Entwicklungsumgebung (app.dev.secpaid.com) mit einem Tool wie ngrok oder webhook.site um Webhooks lokal zu empfangen:

  1. ngrok starten: ngrok http 8000
  2. Ihren paymentEndpoint auf die ngrok-URL setzen
  3. Test-Link erstellen und mit einer Testkarte bezahlen
  4. Den Webhook auf Ihrem lokalen Server beobachten

Webhooks erneut senden

Wenn Sie einen Webhook verpasst haben, können Sie ihn manuell erneut auslösen:

curl -X POST https://app.secpaid.com/api/v2/sendWebhookViaPayId \
  -H "Content-Type: application/json" \
  -H "token: IHR_TOKEN" \
  -d '{"pay_ids": "12345"}'

Best Practices

  1. Schnell antworten — Sofort 200 zurückgeben, bei Bedarf asynchron verarbeiten
  2. Idempotenz — Doppelte Webhooks elegant behandeln (gleiche pay_id kann mehrfach ankommen)
  3. Zahlung verifizieren — Prüfen dass pay_id zu einer erstellten Bestellung passt
  4. HTTPS verwenden — In Produktion immer TLS nutzen
  5. Alles loggen — Rohe Webhook-Payloads zum Debuggen speichern
  6. Nicht auf Reihenfolge verlassen — Der Webhook kann vor oder nach dem callback_url-Redirect ankommen