Overview
Once you’ve registered a webhook endpoint, Modulus Labs sends POST requests to your server whenever QR Ph transactions complete. This guide covers how to receive, decrypt, and process these webhooks securely.1
Receive POST Request
Your server receives a POST request with an encrypted JWE payload
2
Decrypt Payload
Use your secret key to decrypt the JWE-encrypted transaction data
3
Validate Data
Verify the webhook is authentic and hasn’t been processed before
4
Process Transaction
Update order status, send confirmations, trigger fulfillment
5
Respond Quickly
Return 200 OK within 10 seconds to acknowledge receipt
Webhook Request Format
Modulus Labs sends webhooks as POST requests with this structure:Request Headers
string
required
Always
application/jsonstring
Merchant activation code (for multi-merchant setups). Present if you specified an activation code when creating the webhook.
Request Body
string
required
JWE-encrypted transaction payload. You must decrypt this using your secret key to access the actual transaction data.
Decrypting Webhook Payloads
All webhook payloads are encrypted using JWE (JSON Web Encryption) with:- Content Encryption:
A256CBC-HS512(AES-256-CBC with HMAC SHA-512) - Key Encryption:
A256KW(AES-256 Key Wrap)
Decryption Examples
Decrypted Payload Structure
After decryption, the webhook payload contains these fields:string
required
The webhook action type:
QRPH_SUCCESS or QRPH_DECLINEDstring
required
Unique reference number for this transaction. Matches the referenceNumber from your Create Dynamic QR Ph request.Example:
"REF-20240115-ABC123"integer
required
Transaction amount in the smallest currency unit (centavos for PHP).Example:
100000 (₱1,000.00)string
required
Three-letter ISO currency code.Example:
"PHP"string
required
ISO 8601 timestamp of when the transaction was processed.Example:
"2024-01-15T14:30:00Z"string
required
Transaction status:
SUCCESS, FAILED, PENDING, or REQUIRES_ACTIONstring
required
Your merchant identifier.Example:
"MERCH12345"string
Name of the customer who made the payment (if available from the bank).
string
Name of the bank the customer used to pay (if available).
Example Payload: Successful Payment
Example Payload: Declined Payment
Processing Webhooks
Handle Different Webhook Actions
Idempotency and Duplicate Handling
Modulus Labs may send the same webhook multiple times due to retries. Implement idempotency to prevent duplicate processing.Idempotency Strategies
- Database Unique Constraint
- Check Before Processing
- Transaction-Based
Webhook Retry Mechanism
If your endpoint doesn’t respond with200 OK, Modulus Labs automatically retries:
What Triggers a Retry?
- Your server returns a status code other than
2xx(e.g.,500,503,404) - Connection timeout (no response within 10 seconds)
- Network errors (DNS failure, connection refused, etc.)
Best Practices for Retries
Respond with 200 OK Even on Business Logic Failures
Respond with 200 OK Even on Business Logic Failures
Return Why? Retrying won’t fix business logic errors (e.g., order not found, inventory depleted). Handle these gracefully without triggering retries.
200 OK to acknowledge webhook receipt, even if your business logic fails:Return 5xx Only for Temporary Failures
Return 5xx Only for Temporary Failures
Use
500/503 status codes only when retrying might help:Log All Webhook Deliveries
Log All Webhook Deliveries
Track webhook deliveries to monitor retry patterns:Use this data to:
- Identify chronic processing failures
- Detect unusual retry patterns
- Debug webhook issues
Implement Exponential Backoff for External Calls
Implement Exponential Backoff for External Calls
If your webhook handler calls external services, add retry logic:
Response Requirements
Successful Response
Return200 OK with a JSON body:
The response body content doesn’t matter - Modulus Labs only checks the status code. However, returning JSON is a good practice for debugging.
Response Timing
Asynchronous Processing
For long-running operations, respond immediately and process asynchronously:Security Best Practices
Verify JWE Encryption
Always decrypt the JWE payload. Never trust unencrypted webhook data - it could be forged.
Validate Payload Structure
Verify the decrypted payload contains expected fields before processing.
Check Reference Number
Confirm the referenceNumber exists in your system before fulfilling orders.
Implement Rate Limiting
Limit webhook requests per IP to prevent abuse and DDoS attacks.
Use HTTPS Only
Reject non-HTTPS webhook URLs in production to prevent man-in-the-middle attacks.
Log Everything
Log all webhook receipts, decryption attempts, and processing results for audit trails.
Error Handling
Graceful Error Recovery
Testing Your Webhook Handler
Local Testing with ngrok
1
Install ngrok
2
Start Your Webhook Server
3
Expose with ngrok
4
Register Webhook URL
5
Test with Simulate API
Monitoring and Alerting
Set up monitoring to detect webhook issues:Track Processing Success Rate
Track Processing Success Rate
Monitor Processing Time
Monitor Processing Time
Detect Decryption Failures
Detect Decryption Failures
Track Webhook Delays
Track Webhook Delays
Next Steps
Payload Structure
Complete webhook payload reference
Setup Guide
Register webhook endpoints
Simulate API
Test webhooks in sandbox
Webhook API Reference
Manage webhooks programmatically