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¶
- Melden Sie sich in Ihrem SecPaid-Konto an
- Navigieren Sie zu Settings → API & Integrations
- Geben Sie Ihre Webhook-URL im Feld Payment Endpoint ein
- Klicken Sie auf Save Settings
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) |
Split-Link-Webhooks¶
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 Gesamtbetraguser_id— die User-ID des Empfängersnote— dierecipient_notevom 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:
- JSON-kodiert
- Mit AES-256-CBC unter Verwendung Ihres
EncryptionKeyverschlüsselt - Base64-kodiert
- 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:
- ngrok starten:
ngrok http 8000 - Ihren
paymentEndpointauf die ngrok-URL setzen - Test-Link erstellen und mit einer Testkarte bezahlen
- 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¶
- Schnell antworten — Sofort 200 zurückgeben, bei Bedarf asynchron verarbeiten
- Idempotenz — Doppelte Webhooks elegant behandeln (gleiche
pay_idkann mehrfach ankommen) - Zahlung verifizieren — Prüfen dass
pay_idzu einer erstellten Bestellung passt - HTTPS verwenden — In Produktion immer TLS nutzen
- Alles loggen — Rohe Webhook-Payloads zum Debuggen speichern
- Nicht auf Reihenfolge verlassen — Der Webhook kann vor oder nach dem
callback_url-Redirect ankommen