Skip to main content

Tutorial: Verify a Webhook Signature

This tutorial walks you through testing webhook delivery and verifying a webhook signature end to end. You will use webhook.site as a test endpoint to inspect incoming payloads without building a server.

Time to complete: 15 minutes

Prerequisites:

  • A Payrail account and JWT token
  • A REST client such as Postman
  • A free webhook.site account

Step 1 — Set up a test endpoint​

Go to webhook.site. The page immediately generates a unique URL for you:

https://webhook.site/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Copy this URL — you will use it as your webhook endpoint. Any POST request sent to this URL will appear in the webhook.site dashboard in real time.


Step 2 — Configure your webhook secret​

Add your webhook URL and secret to your environment configuration:

WEBHOOK_SECRET=your-webhook-secret
WEBHOOK_URL=https://webhook.site/your-unique-id

Note: Use the full webhook.site URL without the #!/view/ path. For example:

  • ✅ Correct: https://webhook.site/87d0ec0c-95fd-4cbc-baef-632f1a5e50f5
  • ❌ Incorrect: https://webhook.site/#!/view/87d0ec0c-95fd-4cbc-baef-632f1a5e50f5

Restart the server after updating your environment variables.


Step 3 — Create a test transaction​

First register a customer and add a payment method if you haven't already. Then create a transaction:

Request

POST /api/transactions
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
Idempotency-Key: webhook-test-001

{
"customer": "YOUR_CUSTOMER_ID",
"paymentMethod": "YOUR_PAYMENT_METHOD_ID",
"amount": 15000,
"currency": "USD",
"description": "Webhook test payment"
}

Response

{
"_id": "69ba9d3e199bf8e79a8050e7",
"customer": "69ba9a90199bf8e79a8050e1",
"paymentMethod": "69ba9cef199bf8e79a8050e4",
"amount": 15000,
"currency": "USD",
"status": "pending",
"description": "Webhook test payment",
"createdAt": "2026-03-18T12:40:30.061Z"
}

Copy the _id from the response — you will need it in the next step.


Step 4 — Trigger the webhook​

Update the transaction status to completed. This triggers the payment.succeeded webhook event.

Request

PUT /api/transactions/YOUR_TRANSACTION_ID
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json

{
"status": "completed"
}

Response

{
"_id": "69ba9d3e199bf8e79a8050e7",
"status": "completed"
}

Step 5 — Inspect the payload​

Go to webhook.site. You should see a new POST request appear in the left panel within a few seconds.

Click on the POST entry to inspect the payload:

{
"event": "payment.succeeded",
"created_at": "2026-03-18T12:46:55.681Z",
"data": {
"_id": "69ba9d3e199bf8e79a8050e7",
"customer": "69ba9a90199bf8e79a8050e1",
"paymentMethod": "69ba9cef199bf8e79a8050e4",
"amount": 15000,
"currency": "USD",
"status": "completed",
"description": "Webhook test payment",
"createdAt": "2026-03-18T12:40:30.061Z"
}
}

Check the request headers for the X-Payrail-Signature header:

X-Payrail-Signature: sha256=abc123...

This signature was generated by Payrail using HMAC-SHA256 and your webhook secret. In production, your server verifies this signature before processing the event.


Step 6 — Verify the signature in code​

In production you would verify the signature on your server before processing the event. Here is how to do that in Node.js and Python.

Node.js

const crypto = require('crypto');

function verifySignature(rawBody, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(rawBody);
const expected = `sha256=${hmac.digest('hex')}`;
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}

Python

import hmac
import hashlib

def verify_signature(raw_body, signature, secret):
hmac_obj = hmac.new(
secret.encode('utf-8'),
raw_body,
hashlib.sha256
)
expected = f"sha256={hmac_obj.hexdigest()}"
return hmac.compare_digest(expected, signature)

Important: Always verify the signature against the raw request body — not the parsed JSON. See Webhooks for complete implementation examples.


What you learned​

  • How to use webhook.site to test webhook delivery without building a server
  • How Payrail signs webhook payloads using HMAC-SHA256
  • How to inspect a live webhook payload and signature
  • How to verify a signature in Node.js and Python

Next steps​