How to set up, verify, test, and monitor PayPal webhooks — plus why you should migrate from IPN.
Last updated March 2026. Covers PayPal REST API v2 and Webhooks API.
PayPal offers two notification systems. IPN (Instant Payment Notification) is the legacy approach. Webhooks are the modern replacement. PayPal recommends webhooks for all new integrations.
| Feature | IPN (Legacy) | Webhooks (Modern) |
|---|---|---|
| Data format | Form-encoded POST | JSON |
| Verification | POST back to PayPal to confirm | Certificate-based signature in headers |
| Event selection | All-or-nothing | Subscribe to specific event types |
| Multiple endpoints | One URL only | Multiple webhook listeners |
| Retry behavior | Limited retries | Automatic retries with backoff for up to 3 days |
| API version | Classic NVP/SOAP | REST API v2 |
Migration note: If you are still using IPN, plan to migrate. PayPal has been deprecating Classic APIs and IPN may stop working for newer payment products. Webhooks give you structured JSON, better reliability, and fine-grained event filtering.
PayPal has dozens of event types. Here are the most commonly used ones:
By use case:
PAYMENT.SALE.COMPLETED, PAYMENT.CAPTURE.COMPLETED, PAYMENT.CAPTURE.DENIEDCHECKOUT.ORDER.APPROVED, CHECKOUT.ORDER.COMPLETEDBILLING.SUBSCRIPTION.CREATED, BILLING.SUBSCRIPTION.CANCELLED, BILLING.SUBSCRIPTION.PAYMENT.FAILEDCUSTOMER.DISPUTE.CREATED, CUSTOMER.DISPUTE.RESOLVEDTo configure webhooks in PayPal:
developer.paypal.com.PAYMENT.CAPTURE.COMPLETED).Remember: PayPal has separate Sandbox and Live environments. Configure webhooks in both if you need to test and receive production notifications.
PayPal uses certificate-based signature verification, which is more complex than the HMAC approach used by Stripe or GitHub. Each webhook request includes these headers:
Paypal-Transmission-Sig — the signaturePaypal-Cert-Url — URL of the signing certificatePaypal-Transmission-Id — unique transmission IDPaypal-Transmission-Time — timestampPaypal-Auth-Algo — the algorithm (typically SHA256withRSA)Verification concept:
// The verification message PayPal signs is:
// transmissionId + "|" + timestamp + "|" + webhookId + "|" + crc32(body)
//
// To verify manually:
// 1. Download the cert from Paypal-Cert-Url
// 2. Validate the cert chains to PayPal's root CA (symantec/verisign)
// 3. Construct the expected message string
// 4. Verify the Paypal-Transmission-Sig against the message
// using the public key from the certificate
// In practice, use PayPal's verify-webhook-signature API:
POST /v1/notifications/verify-webhook-signature
{
"auth_algo": "SHA256withRSA",
"cert_url": "https://api.paypal.com/...",
"transmission_id": "...",
"transmission_sig": "...",
"transmission_time": "...",
"webhook_id": "YOUR_WEBHOOK_ID",
"webhook_event": { /* the full event body */ }
}
Recommendation: Use the PayPal SDK or the verify-webhook-signature API endpoint rather than implementing cert verification yourself. Manual cert validation requires downloading certificates, checking the chain of trust, and handling cert rotation — the SDK handles all of this for you.
// Node.js example using PayPal REST SDK
const paypal = require('@paypal/checkout-server-sdk');
app.post('/webhook/paypal', express.json(), async (req, res) => {
const headers = {
'paypal-auth-algo': req.headers['paypal-auth-algo'],
'paypal-cert-url': req.headers['paypal-cert-url'],
'paypal-transmission-id': req.headers['paypal-transmission-id'],
'paypal-transmission-sig': req.headers['paypal-transmission-sig'],
'paypal-transmission-time': req.headers['paypal-transmission-time'],
};
// Call PayPal's verification API
const response = await fetch(
'https://api-m.paypal.com/v1/notifications/verify-webhook-signature',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken,
},
body: JSON.stringify({
auth_algo: headers['paypal-auth-algo'],
cert_url: headers['paypal-cert-url'],
transmission_id: headers['paypal-transmission-id'],
transmission_sig: headers['paypal-transmission-sig'],
transmission_time: headers['paypal-transmission-time'],
webhook_id: 'YOUR_WEBHOOK_ID',
webhook_event: req.body,
}),
}
);
const result = await response.json();
if (result.verification_status === 'SUCCESS') {
// Process the verified event
console.log('Event type:', req.body.event_type);
res.status(200).json({ received: true });
} else {
console.error('Verification failed');
res.status(401).json({ error: 'Invalid signature' });
}
});
Testing PayPal webhooks during development requires a public URL. Here is the fastest approach:
PAYMENT.CAPTURE.COMPLETED).For local development, forward webhooks from your SDNBros endpoint directly to your local server with sdnbros tunnel.
PayPal webhooks can fail silently — a missed CUSTOMER.DISPUTE.CREATED event means you lose the dispute response window. Set up monitoring:
Create a free SDNBros account to start monitoring your PayPal webhooks in production.
| Error | Cause | Fix |
|---|---|---|
| VERIFICATION_FAILURE | Wrong Webhook ID, or cert URL blocked by firewall | Double-check your Webhook ID in the PayPal Dashboard. Ensure your server can reach api.paypal.com to download certs. |
| Webhook timeout | Endpoint takes too long to respond (PayPal expects response within 30s) | Return 200 immediately and process the event asynchronously in a background job. |
| Duplicate events | PayPal retries on non-2xx. Your handler processes the same event twice. | Store the transmission_id or event id and check for duplicates. Make your handler idempotent. |
| Sandbox vs Live mismatch | Webhook configured in Sandbox but triggered by Live transaction (or vice versa) | Configure webhooks separately in both Sandbox and Live apps. Verify the correct environment. |
| Events not arriving | Wrong event types selected, or webhook disabled after repeated failures | Check the Webhooks section in the Developer Dashboard. Re-enable the webhook and verify event type selection. |
Create a public endpoint and inspect PayPal events. No signup is needed for the tester.
Open Webhook Tester Monitor in ProductionRelated guides: What is a Webhook? · Webhook vs API · Webhook Security · Retry Strategies · Stripe · GitHub · Shopify · Slack
More: What is a Webhook? | Webhook Security Guide | Webhook Idempotency | Compare Tools