Skip to content

Set Up Webhooks

Webhooks let Plirin notify your server when events happen — a payment succeeds, an invoice is paid, a refund is processed. Instead of polling, you receive a signed HTTP POST with event data in real-time.

  1. Go to Settings

    In the dashboard sidebar, click Settings and scroll to the Webhooks section.

  2. Add an endpoint

    Click Add Endpoint and enter:

    • URL — your server’s endpoint (e.g., https://yourapp.com/webhooks/plirin)
    • Events — select which events to subscribe to (or choose “All events”)

    Click Create to save the endpoint.

  3. Copy your signing secret

    After creating the endpoint, Plirin generates a unique signing secret. Copy it and store it securely in your server’s environment variables — you’ll need it to verify webhook signatures.

  4. Implement your receiver

    Your endpoint must:

    • Accept POST requests with Content-Type: application/json
    • Verify the X-Plirin-Signature header (see below)
    • Return a 200 status code to acknowledge receipt
  5. Verify signatures

    Every webhook includes a signature header for authenticity. Here’s how to verify it:

    import hashlib, hmac, time
    def verify_webhook(secret, sig_header, body, max_skew=300):
    parts = dict(p.split("=", 1) for p in sig_header.split(","))
    ts, v1 = int(parts["t"]), parts["v1"]
    if abs(int(time.time()) - ts) > max_skew:
    return False
    expected = hmac.new(
    secret.encode(),
    f"{ts}.".encode() + body,
    hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, v1)
  6. Test your endpoint

    Send a test event from the Webhooks settings page to verify your endpoint receives and acknowledges it.

Delivery is asynchronous: Plirin queues the event and a delivery worker sends it, normally within a second. Your endpoint being slow never delays the payment itself.

If your endpoint doesn’t respond with a 2xx status within 10 seconds, Plirin retries with exponential backoff:

  • Attempt 1: immediate
  • Attempt 2: 1 minute
  • Attempt 3: 5 minutes
  • Attempt 4: 30 minutes
  • Attempt 5: 2 hours
  • Attempt 6: 24 hours

After 6 failed attempts the delivery is marked exhausted. You can replay it from the dashboard.

Delivery is at-least-once, so handlers must be idempotent — deduplicate on the X-Plirin-Delivery-ID header. See Delivery & Retries for the full state list.