PayPal Webhook events not being triggered in Sandbox mode

1.2k Views Asked by At

I am using the PayPal Rest API, more specific the PayPal .Net SDK for my project and I like it a lot.

My problem is that I am not able to receive any webhook notifications from PayPal until now.

Note: The webhook simulator however does work, my handler receives the json post properly from PayPal.

These are the steps I take:

  1. After successfully creating a new invoice (using sandbox credentials from my paypal app), I send it to the test buyer account.

  2. I open the url from the notification to view the invoice and I pay it using the buyer test account.

  3. Both facilitator and buyer get notified that the invoice has been paid successfully.

  4. Nothing happens at my server. No webhook event requests are being received at my listener endpoint.

I have an active webhook event listener in my app's sandbox configuration, tracking all possible events.

What could be the reason that no events are being fired by PayPal?

I do not want to switch to IPN yet, and periodically iterating over a list of invoices from a search result is not an efficient alternative either.


Update:

Since the sandbox webhook event server is up and running again, I got it to work using the following code (c# controller action). Pay attention that the json body structure fired from the webhook simulator is different from the one sent after paying an invoice. Therefore I extended the WebHookEvt object from the PayPal SDK accordingly.

        /// <summary>
    /// PayPal Webhook handler
    /// </summary>
    /// <param name="evt"></param>
    /// <returns></returns>
    [HttpPost]
    public ActionResult EventHandler(WebhookEvent evt) { // [System.Web.Http.FromBody]

        string json = null;
        Capture capture = null;
        InvoiceObject invoiceObject = null;
        InvoiceExt invoice = null;
        WebHookEventCapture captureEvent = null;
        WebHookEventInvoice invoiceEvent = null;

        if (evt == null) {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        } else {
            this.logger.Debug(string.Format("***** Webhook event type [{0}] received from PayPal *****", evt.event_type));
            logger.Debug(string.Format("Event id: {0}", evt.id));
            logger.Debug(string.Format("Event create time: {0}", evt.create_time));
            logger.Debug(string.Format("Event type: {0}", evt.event_type));
            logger.Debug(string.Format("Event resource: {0}", evt.resource));
            logger.Debug(string.Format("Event resource type: {0}", evt.resource_type));
            logger.Debug(string.Format("Event summary: {0}", evt.summary));

            using (Stream req = Request.InputStream) {
                req.Seek(0, System.IO.SeekOrigin.Begin);
                using (StreamReader sr = new StreamReader(req)) {
                    json = sr.ReadToEnd();
                }
            }

            logger.Debug(string.Format("WebHook request json form PayPal: ***{0}***", json));

            // Validate webhook event
            bool isValid = WebhookEvent.ValidateReceivedEvent(new PayPalPaymentProvider(IPN_SANDBOX_MODE).Context, Request.Headers, json, WEBHOOK_ID_INVOICE_PAID);
            logger.Debug(string.Format("Validating webhook event... Is valid = {0}", isValid ? "TRUE" : "FALSE"));                

            try {
                if ("capture".Equals(evt.resource_type)) {
                    captureEvent = JsonConvert.DeserializeObject<WebHookEventCapture>(json);
                    capture = captureEvent.resource;
                } else if ("invoices".Equals(evt.resource_type)) {
                    invoiceEvent = JsonConvert.DeserializeObject<WebHookEventInvoice>(json);
                    invoiceObject = invoiceEvent.resource;
                    invoice = invoiceObject.invoice;
                }

                //if (capture != null) {
                //    logger.Debug(string.Format("Capture amount: {0}", capture.amount));
                //    logger.Debug(string.Format("Capture create time: {0}", capture.create_time));
                //    logger.Debug(string.Format("Capture id: {0}", capture.id));
                //    logger.Debug(string.Format("Capture is final: {0}", capture.is_final_capture.HasValue ? capture.is_final_capture : false));
                //    logger.Debug(string.Format("Capture parent payment: {0}", capture.parent_payment));
                //    logger.Debug(string.Format("Capture state: {0}", capture.state));
                //    logger.Debug(string.Format("Capture transaction fee: {0}", capture.transaction_fee));
                //    logger.Debug(string.Format("Capture update time: {0}", capture.update_time));
                //}

                if (isValid && invoice != null) {
                    logger.Debug(string.Format("Invoice [{0}]", invoice));
                    logger.Debug(string.Format("Invoice id: [{0}]", invoice.id));
                    logger.Debug(string.Format("Invoice merchant memo: [{0}]", invoice.merchant_memo));
                    logger.Debug(string.Format("Invoice date: [{0}]", invoice.invoice_date));
                    logger.Debug(string.Format("Invoice status: [{0}]", invoice.status));
                    logger.Debug(string.Format("Invoice total amount: [{0}]", invoice.total_amount != null ? invoice.total_amount.currency + invoice.total_amount.value : "??"));
                    if (invoice.billingInfo != null) { // billing_info
                        foreach (var billingInfo in invoice.billingInfo) {
                            logger.Debug(string.Format("Invoice billing info address: {0}", billingInfo.address ?? new InvoiceAddress()));
                            logger.Debug(string.Format("Invoice billing info business name: {0}", billingInfo.business_name ?? "??"));
                            logger.Debug(string.Format("Invoice billing info email: {0}", billingInfo.email ?? "??"));
                            logger.Debug(string.Format("Invoice billing info first name: {0}", billingInfo.first_name ?? "??"));
                            logger.Debug(string.Format("Invoice billing info last name: {0}", billingInfo.last_name ?? "??"));
                            logger.Debug(string.Format("Invoice billing info language: {0}", billingInfo.language ?? "??"));
                            logger.Debug(string.Format("Invoice billing info notification channel: {0}", billingInfo.notification_channel ?? "??"));
                            logger.Debug(string.Format("Invoice billing info phone: {0}", billingInfo.phone ?? new Phone()));
                        }
                    }

                    // Update clientproductpayment
                    SubscriptionRepository db = new SubscriptionRepository();
                    var subscription = db.Context.ClientProductPayments.Where(
                                q => invoice.id.Equals(q.TransactionId)).FirstOrDefault();
                    if (subscription != null) {
                        logger.Debug(string.Format("Subscription (ClientProductPayment) with transaction_id = [{0}] found", invoice.id));

                        // Update subscription
                        db.RegisterPayment(subscription, invoice.id);

                        logger.Debug(string.Format(
                            "Subscription (ClientProductPayment) with id = [{0}] updated successfully with transaction id = [{1}]",
                                subscription.Id, invoice.id));

                    } else {
                        logger.Warn(string.Format("Subscription (ClientProductPayment) with transaction_id = [{0}] not found", invoice.id));
                    }

                }

            }
            catch (Exception e) {
                logger.Error(e.Message, e);
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

        }
        logger.Debug("Sending Http status code 200 response...");
        return new HttpStatusCodeResult(HttpStatusCode.OK);            
    }

Extending WebHookEvt

using Newtonsoft.Json;
using PayPal.Api;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PaymentManager.Provider {
    public class WebHookEventCapture : WebhookEvent {

        [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "resource")]
        public new Capture resource { get; set; }

    }

    public class WebHookEventInvoice : WebhookEvent {

        [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "resource")]
        public new InvoiceObject resource { get; set; }

    }

    public class InvoiceObject {

        [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "invoice")]
        public InvoiceExt invoice { get; set; }

    }

    public class InvoiceExt : Invoice {

        [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "billingInfo")]
        public List<BillingInfo> billingInfo { get; set; }

    }

}
1

There are 1 best solutions below

4
On

We are sorry about that. There was a temporary issue at our end which has been fixed. You should be able to receive Invoicing webhook notifications now. Please try them and let us know how it goes.

Thanks