TL;DR;
PayPal requires that all the webhook notification messages it sends be verified by the webhook listener receiving these messages.
This requirement enhances security by ensuring that your webhook listener is receiving authentic PayPal webhook messages.
PayPal has updated its endpoint for verifying PayPal webhook notification messages, and its old webhook verification method is now deprecated. The updated endpoint simplifies the process of verifying PayPal webhook messages, which improves the developer experience.
The update also incorporates a lot more of our REST APIs (such as the Orders API). You may learn more about the update rationale here.
A webhook is an automated HTTP request sent from an application when triggered by an event. This request carries a message (called a payload) to a unique destination URL (called a webhook listener), and the receiving application can take further actions based on the payload content. Webhooks allow applications to communicate seamlessly with each other and enable speed in processing and service delivery.
PayPal’s REST APIs use webhooks to notify your application that an event has occurred; for example, a new order has been placed, or a payment has been processed. You can create a webhook associated with an event in your PayPal Developer Portal account. PayPal webhooks support an extensive list of event types.
An unscrupulous player could spoof a webhook notification message and attempt to make the message appear as it originated from PayPal. Therefore, to ensure security, PayPal requires that applications verify all webhook notifications received from PayPal.
To verify the PayPal webhook message, your application sends a POST request to PayPal’s verify-webhook-signature
endpoint with a payload containing several required parameters:
-
auth_algo
extracted from thePAYPAL-AUTH-ALGO
value in the webhook response header. -
cert_url
extracted from thePAYPAL-CERT-URL
value in the webhook response header. -
transmission_id
extracted from thePAYPAL-TRANSMISSION-ID
value in the webhook response header. -
transmission_sig
extracted from thePAYPAL-TRANSMISSION-SIG
value in the webhook response header. -
transmission_time
extracted from thePAYPAL-TRANSMISSION-TIME
value in the webhook response header. -
webhook_id
The ID of the webhook as configured in your PayPal Developer Portal account. -
webhook_event
This is the webhook notification response received from PayPal, which you are now verifying.
Here is a sample webhook verification payload:
{
"auth_algo": "SHA256withRSA",
"cert_url": "cert_url",
"transmission_id": "69cd13f0-d67a-11e5-baa3-778b53f4ae55",
"transmission_sig":
"lmI95Jx3Y9nhR5SJWlHVIWpg4AgFk7n9bCHSRxbrd8A9zrhdu2rMyFrmz+Zjh3s3boXB07VXCXUZy/UFzUlnGJn0wDugt7FlSvdKeIJenLRemUxYCPVoEZzg9VFNqOa48gMkvF+XTpxBeUx/kWy6B5cp7GkT2+pOowfRK7OaynuxUoKW3JcMWw272VKjLTtTAShncla7tGF+55rxyt2KNZIIqxNMJ48RDZheGU5w1npu9dZHnPgTXB9iomeVRoD8O/jhRpnKsGrDschyNdkeh81BJJMH4Ctc6lnCCquoP/GzCzz33MMsNdid7vL/NIWaCsekQpW26FpWPi/tfj8nLA==",
"transmission_time": "2016-02-18T20:01:35Z",
"webhook_id": "1JE4291016473214C",
"webhook_event": {
"id": "8PT597110X687430LKGECATA",
"create_time": "2013-06-25T21:41:28Z",
"resource_type": "authorization",
"event_type": "PAYMENT.AUTHORIZATION.CREATED",
"summary": "A payment authorization was created",
"resource": {
"id": "2DC87612EK520411B",
"create_time": "2013-06-25T21:39:15Z",
"update_time": "2013-06-25T21:39:17Z",
"state": "authorized",
"amount": {
"total": "7.47",
"currency": "USD",
"details": {
"subtotal": "7.47"
}
},
"parent_payment": "PAY-36246664YD343335CKHFA4AY",
"valid_until": "2013-07-24T21:39:15Z",
"links": [
{
"href": "https://api-m.paypal.com/v1/payments/authorization/2DC87612EK520411B",
"rel": "self",
"method": "GET"
},
{
"href": "https://api-m.paypal.com/v1/payments/authorization/2DC87612EK520411B/capture",
"rel": "capture",
"method": "POST"
},
{
"href": "https://api-m.paypal.com/v1/payments/authorization/2DC87612EK520411B/void",
"rel": "void",
"method": "POST"
},
{
"href": "https://api-m.paypal.com/v1/payments/payment/PAY-36246664YD343335CKHFA4AY",
"rel": "parent_payment",
"method": "GET"
}
]
}
}
}
Here is a sample POST request verifying a PayPal webhook notification, sent from a NodeJS application:
var fetch = require('node-fetch');
fetch('https://api-m.sandbox.paypal.com/v1/notifications/verify-webhook-signature', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ECvJ_yBNz_UfMmCvWEbT_2ZWXdzbFFQZ-1Y5K2NGgeHn'
},
body: JSON.stringify({ "transmission_id": "69cd13f0-d67a-11e5-baa3-778b53f4ae55", "transmission_time": "2016-02-18T20:01:35Z", "cert_url": "cert_url", "auth_algo": "SHA256withRSA", "transmission_sig": "lmI95Jx3Y9nhR5SJWlHVIWpg4AgFk7n9bCHSRxbrd8A9zrhdu2rMyFrmz+Zjh3s3boXB07VXCXUZy/UFzUlnGJn0wDugt7FlSvdKeIJenLRemUxYCPVoEZzg9VFNqOa48gMkvF+XTpxBeUx/kWy6B5cp7GkT2+pOowfRK7OaynuxUoKW3JcMWw272VKjLTtTAShncla7tGF+55rxyt2KNZIIqxNMJ48RDZheGU5w1npu9dZHnPgTXB9iomeVRoD8O/jhRpnKsGrDschyNdkeh81BJJMH4Ctc6lnCCquoP/GzCzz33MMsNdid7vL/NIWaCsekQpW26FpWPi/tfj8nLA==", "webhook_id": "1JE4291016473214C", "webhook_event": { "id": "8PT597110X687430LKGECATA", "create_time": "2013-06-25T21:41:28Z", "resource_type": "authorization", "event_type": "PAYMENT.AUTHORIZATION.CREATED", "summary": "A payment authorization was created", "resource": { "id": "2DC87612EK520411B", "create_time": "2013-06-25T21:39:15Z", "update_time": "2013-06-25T21:39:17Z", "state": "authorized", "amount": { "total": "7.47", "currency": "USD", "details": { "subtotal": "7.47" } }, "parent_payment": "PAY-36246664YD343335CKHFA4AY", "valid_until": "2013-07-24T21:39:15Z", "links": [ { "href": "https://api-m.paypal.com/v1/payments/authorization/2DC87612EK520411B", "rel": "self", "method": "GET" }, { "href": "https://api-m.paypal.com/v1/payments/authorization/2DC87612EK520411B/capture", "rel": "capture", "method": "POST" }, { "href": "https://api-m.paypal.com/v1/payments/authorization/2DC87612EK520411B/void", "rel": "void", "method": "POST" }, { "href": "https://api-m.paypal.com/v1/payments/payment/PAY-36246664YD343335CKHFA4AY", "rel": "parent_payment", "method": "GET" } ] } } })
});
When your webhook verification request is successful, PayPal responds with the following payload (and an HTTP status of 200):
{
"verification_status": "SUCCESS"
}
PayPal has a webhook simulator with which you can quickly test your webhook listener. Grab the URL of your webhook listener, or grab a mock listener URL from services like https://webhook.site. In the webhook simulator, enter this URL in the Webhooks URL field, select the Event Type for which you want a notification message, then click Send Test:
Your webhook listener should receive a mock payload from PayPal that resembles the examples provided earlier in this post.
PayPal takes the security of our products very seriously; with this update to our webhook verification endpoint, we continue to provide seamless payment integrations, coupled with mission-critical quality security standards.
Join the PayPal Developer Community
Our Developer Community members support each other in integrating PayPal technologies, contributing to open source, expanding knowledge and networks, and improving PayPal's products and documentation. We'd love to have you join us! 💙
- Website: https://developer.paypal.com
- Twitter: @paypaldev
- GitHub: @paypal
Top comments (5)
just want to ask if you have tried that with the latest Subscription API? Seems nothing is firing from Paypal's end.
Apologies for the late response, are you still having this issue? If so, we will check on this one for you.
Yes, when I create a Subscription Plan -> Subscriptions in my Sandbox and create a webhook from a developer console as per instruction, I'm assuming the webhook is called from the Subscriptions event. But if I rather create a Subscription button and specify my URL to the notify_url parameter the webhook works fine but the payload is old version.
Hello @jared201 do you have a code snippet, or perhaps a video, detailing this bug that you are experiencing? I could pass it along to our Subscriptions team.
Sounds good