Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.payreque.st/llms.txt

Use this file to discover all available pages before exploring further.

Webhooks

PayRequest can send a signed HTTP POST to your endpoint when a payment succeeds. Use this to automate fulfillment, update your database, or trigger downstream workflows without polling.

Setup

  1. Go to Settings → API & MCP in your PayRequest dashboard
  2. Scroll down to the Webhooks section
  3. Enter your endpoint URL (must be publicly reachable over HTTPS)
  4. Click Save — a signing secret is generated automatically
  5. Copy the Signing Secret and store it securely in your environment

Verifying signatures

Every request includes an X-PayRequest-Signature header containing an HMAC-SHA256 signature of the raw request body. Always verify this before processing the event.
X-PayRequest-Signature: sha256=a1b2c3d4...
$secret   = $_ENV['PAYREQUEST_WEBHOOK_SECRET'];
$body     = file_get_contents('php://input');
$received = $_SERVER['HTTP_X_PAYREQUEST_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);

if (!hash_equals($expected, $received)) {
    http_response_code(401);
    exit;
}

$event = json_decode($body, true);
Always use a timing-safe comparison (hash_equals, hmac.compare_digest, timingSafeEqual) to prevent timing attacks.

Event: payment.succeeded

Fired when a transaction status changes to paid. Delivered asynchronously via the queue (typically within seconds).

Payload

{
  "event": "payment.succeeded",
  "timestamp": "2026-05-30T12:00:00+02:00",
  "data": {
    "id": 1234,
    "amount": 49.00,
    "currency": "EUR",
    "description": "JMIT-githubuser",
    "payment_link_id": 42,
    "payment_method": "ideal",
    "reference": "tr_abc123",
    "paid_at": "2026-05-30T11:59:45+02:00",
    "customer": {
      "id": 99,
      "name": "Jane Doe",
      "email": "jane@example.com"
    }
  }
}

Fields

FieldTypeDescription
eventstringAlways payment.succeeded
timestampISO 8601When the event was dispatched
data.idintegerTransaction ID
data.amountdecimalAmount paid (e.g. 49.00)
data.currencystring3-letter ISO currency code
data.descriptionstringYour custom reference (e.g. JMIT-githubuser)
data.payment_link_idinteger|nullID of the Smart Link used, if any
data.payment_methodstringPayment method used (e.g. ideal, creditcard)
data.referencestringPayment provider transaction reference
data.paid_atISO 8601Exact time the payment was confirmed
data.customerobject|nullCustomer name, email, and ID

Retries

Webhook delivery is handled by the queue with 3 attempts and a 60-second backoff between retries. If all attempts fail, the event is dropped and a warning is logged. Return any 2xx status code to acknowledge receipt.

Rotating the secret

If your secret is compromised, go to Settings → API & MCP → Webhooks and click Regenerate. Your old secret stops working immediately — update your environment variable before rotating.

Testing locally

Use a tunnel tool to expose your local server during development:
# Using ngrok
ngrok http 8000

# Then set your webhook URL to:
# https://abc123.ngrok.io/webhooks/payrequest