Requirements
- HTTPS endpoint with a stable URL.
- Accept
POSTwithContent-Type: application/json. - Return 2xx quickly (store → ack → process async).
validation_hash.
Documentation Index
Fetch the complete documentation index at: /llms.txt
Use this file to discover all available pages before exploring further.
Minimal, fast, and secure callback handler patterns.
POST with Content-Type: application/json.validation_hash.
import crypto from "node:crypto";
import express from "express";
const app = express();
app.use(express.json({ limit: "256kb" }));
app.post("/webhooks/payments", async (req, res) => {
const body = req.body;
// 1) Basic validation
if (!body?.status || !body?.results?.payment_uuid) {
return res.status(400).send("Invalid payload");
}
// 2) Verify integrity (optional but recommended)
// compute validation_hash as shown in Verify Signature page
// 3) Idempotent persist
await upsertByPaymentUuid(body.results.payment_uuid, body);
// 4) Respond fast
return res.status(202).send("Accepted");
});
app.listen(3000);
from fastapi import FastAPI, Request, HTTPException
app = FastAPI()
@app.post("/webhooks/payments")
async def webhook(req: Request):
body = await req.json()
if "status" not in body or "results" not in body:
raise HTTPException(400, "Invalid payload")
# verify hash (optional), then persist idempotently
save_or_update(body["results"]["payment_uuid"], body)
return {"ok": True}
Route::post('/webhooks/payments', function (Illuminate\Http\Request $request) {
$data = $request->json()->all();
if (!isset($data['status'], $data['results']['payment_uuid'])) {
return response('Invalid payload', 400);
}
// verify hash (optional), then idempotent save
upsert_by_payment_uuid($data['results']['payment_uuid'], $data);
return response()->json(['ok' => true], 202);
});
