My example isn't exactly a webhook per-se, but it works great for me. I put a call to a Firebase Cloud Function call in the onApprove
function like this:
paypal.Buttons({
createSubscription: function(data, actions) {
return actions.subscription.create({
'plan_id': 'P-PLANID'
});
},
onApprove: function(data, actions) {
const orderID = data.orderID;
let url = "myCloudFunction?orderID="+orderID;
//this will verify the purchase and complete order on back end
fetch(url);
//carry on with user experince
}
}).render('#paypal-button-container');
And then verify the purchase using the orderID
in my cloud function, and update my DB or whatever else i need to do like so:
const checkoutNodeJssdk = require('@paypal/checkout-server-sdk');
const functions = require("firebase-functions");
function environment() {
let clientId = process.env.PAYPAL_CLIENT_ID || 'yourClientID';
let clientSecret = process.env.PAYPAL_CLIENT_SECRET || 'yourClientSecret';
return new checkoutNodeJssdk.core.LiveEnvironment(
clientId, clientSecret
);
}
function payPalClient() {
return new checkoutNodeJssdk.core.PayPalHttpClient(environment());
}
exports.completeOrder = functions.https.onRequest((req, res) => {
const orderID = req.query.orderID;
let request = new checkoutNodeJssdk.orders.OrdersGetRequest(orderID);
let order;
try {
order = await payPalClient().execute(request);
console.log(order);
} catch (err) {
console.error(err);
res.send({response: "failed"});
}
if (order.result.status === 'APPROVED') {
//update DB or whatever else needs to happen to complete order
res.send({response: "success"});
} else {
res.send({response: "failed"});
}
});
You can also verify the subscription is active by passing a subscriptionID from the data object returned in the onApprove
function of the button to the cloud function. Use the following to verify the subscription:
async function verifySubscription(subscriptionID, callback) {
const authUrl = "https://api-m.paypal.com/v1/oauth2/token";
const subscriptionsUrl = "https://api.paypal.com/v1/billing/subscriptions/" + subscriptionID;
const clientIdAndSecret = "myClientID:myCLientSecret";
const base64 = Buffer.from(clientIdAndSecret).toString('base64')
fetch(authUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Accept-Language': 'en_US',
'Authorization': `Basic ${base64}`,
},
body: 'grant_type=client_credentials'
}).then(function(response) {
return response.json();
}).then(function(data) {
fetch(subscriptionsUrl, {
method: 'get',
headers: {
'Authorization': 'Bearer '+data.access_token,
'Content-Type': 'application/json'
},
}).then(function(response) {
return response.json();
}).then(function(subscriptionData) {
console.log("subscriptionData.status: ", subscriptionData.status);
if (subscriptionData.status === "ACTIVE") {
callback(true);
} else {
callback(false);
}
}).catch(function(error) {
console.log("couldnt verify subscription");
console.log(error);
callback(false);
});
}).catch(function() {
console.log("couldnt get auth token");
callback(false);
});
}