Handling PayPal Webhooks Prometheus Computing
Handling PayPal Webhooks

Handling PayPal Webhooks

Development

Laravel

Published: May 27, 2024

Author: Andrew Arscott

As this package is built specifically for Laravel, there are routes registered to handle webhook requests into your application. In the installation step, you will have published the config file for this package, if you skipped this step, then you should do it now, as you register your Webhook handlers in this file.

Please note, this feature is not safe to use in Production. It does not yet automatically validate the authenticity of the events, so should only be used in development environments. The next major release will address this issue.

Load the paypal.php config file and look for webhook key and then an array within this with a key of handlers.

They keys in this array are for enum values for the WebhookEventEnum and the value is either a class which implements the HandlesPaypalWebhookEvent interface or a closure which accepts a single param which will be the WebhookEvent.

Adding a closure instead of a class will mean this config file will not be serializeable and therefore you won't be able to cache your config. We recommend using Classes instead of closures for this reason.

Your config file should look something like this:

'webhook' => [
		'handlers' => [
			WebhookEventEnum::CHECKOUT_ORDER_APPROVED->value => PaypalCheckoutOrderApproved::class,
		],
	],

You are free to register as many webhook event handlers here for the given events that this package supports. For a list of the events we currently support, please see below.

Once you have defined all of your webhook events, you can run paypal:webhook-setup in your console to create these webhooks in your PayPal account. Please note, if there are already webhooks setup, this will delete them and recreate only the ones configured in this file. Use caution when running this command especially if you have multiple applications linking to this PayPal account.

The HandlesPaypalWebhookEvent interface requires you to add a handle method which will have a single parameter of $event which is of type WebhookEvent. This event has a method called getResource() which you can call to get the underlying resource associated with the event. For the example below, it would return an Order model:

class PaypalCheckoutOrderApproved implements HandlesPaypalWebhookEvent {

	public function handle(WebhookEvent $event): void {
		$resource = $event->getResource();

		$id = $resource->id;
		$status = $resource->status;
	}
}

Using this you can lookup the order stored in your database, update its status an act accordingly.

The list of events the package currenty supports are type in the WebhookEventEnum enum, which at the time of writing this article, looks like this:

<?php

namespace Drewdan\Paypal\Webhooks\Enums;

enum WebhookEventEnum: string {

	// Payments V2

	case PAYMENT_AUTHORIZATION_CREATED = 'PAYMENT.AUTHORIZATION.CREATED';
	case PAYMENT_AUTHORIZATION_VOIDED = 'PAYMENT.AUTHORIZATION.VOIDED';
	case PAYMENT_CAPTURE_DECLINED = 'PAYMENT.CAPTURE.DECLINED';
	case PAYMENT_CAPTURE_COMPLETED = 'PAYMENT.CAPTURE.COMPLETED';
	case PAYMENT_CAPTURE_PENDING = 'PAYMENT.CAPTURE.PENDING';
	case PAYMENT_CAPTURE_REFUNDED = 'PAYMENT.CAPTURE.REFUNDED';
	case PAYMENT_CAPTURE_REVERSED = 'PAYMENT.CAPTURE.REVERSED';

	// Orders V2

	case CHECKOUT_ORDER_COMPLETED = 'CHECKOUT.ORDER.COMPLETED';
	case CHECKOUT_ORDER_APPROVED = 'CHECKOUT.ORDER.APPROVED';
	case CHECKOUT_ORDER_SAVED = 'CHECKOUT.ORDER.SAVED';
	case CHECKOUT_ORDER_VOIDED = 'CHECKOUT.ORDER.VOIDED';

	case CHECKOUT_PAYMENT_APPROVAL_REVERSED = 'CHECKOUT.PAYMENT-APPROVAL.REVERSED';

	// Disputes

	case CUSTOMER_DISPUTE_CREATED = 'CUSTOMER.DISPUTE.CREATED';

	case CUSTOMER_DISPUTE_RESOLVED = 'CUSTOMER.DISPUTE.RESOLVED';

	case CUSTOMER_DISPUTE_UPDATED = 'CUSTOMER.DISPUTE.UPDATED';

	/**
	 * @deprecated
	 */
	case RISK_DISPUTE_CREATED = 'RISK.DISPUTE.CREATED'; // Deprecated Hook

}