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.
-
Go to Settings
In the dashboard sidebar, click Settings and scroll to the Webhooks section.
-
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.
- URL — your server’s endpoint (e.g.,
-
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.
-
Implement your receiver
Your endpoint must:
- Accept
POSTrequests withContent-Type: application/json - Verify the
X-Plirin-Signatureheader (see below) - Return a
200status code to acknowledge receipt
- Accept
-
Verify signatures
Every webhook includes a signature header for authenticity. Here’s how to verify it:
import hashlib, hmac, timedef 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 Falseexpected = hmac.new(secret.encode(),f"{ts}.".encode() + body,hashlib.sha256,).hexdigest()return hmac.compare_digest(expected, v1)const crypto = require("crypto");function verifyWebhook(secret, sigHeader, bodyBuffer, maxSkew = 300) {const parts = Object.fromEntries(sigHeader.split(",").map((p) => p.split("=", 2)));const ts = parseInt(parts.t, 10);if (Math.abs(Math.floor(Date.now() / 1000) - ts) > maxSkew) return false;const expected = crypto.createHmac("sha256", secret).update(`${ts}.${bodyBuffer}`).digest("hex");return crypto.timingSafeEqual(Buffer.from(expected),Buffer.from(parts.v1));} -
Test your endpoint
Send a test event from the Webhooks settings page to verify your endpoint receives and acknowledges it.
Retry behavior
Section titled “Retry behavior”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.
What’s next?
Section titled “What’s next?”- See all webhook event types for a full reference
- Learn about payload format and data structure
- Read the delivery and retry docs for edge cases