Browse documentationOpen

byrcsc/laravel-payrex · 1.x

Events and listeners.

Listen for typed Laravel PayRex webhook events, inspect their resources, customize event mappings, and design idempotent handlers.

Every verified webhook dispatches PayrexWebhookReceived. When its type exists in config('payrex.webhooks.events'), the package also dispatches the mapped typed event.

Listen for a typed event

namespace App\Listeners;

use App\Models\Order;
use ByRcsc\LaravelPayrex\Events\PaymentIntentSucceeded;
use Illuminate\Contracts\Queue\ShouldQueue;

final class MarkOrderAsPaid implements ShouldQueue
{
    public function handle(PaymentIntentSucceeded $event): void
    {
        $intent = $event->event->paymentIntent();

        if ($intent === null) {
            return;
        }

        Order::query()
            ->where('payrex_payment_intent_id', $intent->id)
            ->whereNull('paid_at')
            ->update(['paid_at' => now()]);
    }
}

Laravel can discover the listener or you can register it explicitly in your application's event configuration.

Default event catalog

PayRex typeLaravel event
payment_intent.awaiting_capturePaymentIntentAwaitingCapture
payment_intent.succeededPaymentIntentSucceeded
setup_intent.succeededSetupIntentSucceeded
checkout_session.expiredCheckoutSessionExpired
refund.createdRefundCreated
refund.updatedRefundUpdated
payout.createdPayoutCreated
payout.depositedPayoutDeposited
billing_statement.createdBillingStatementCreated
billing_statement.updatedBillingStatementUpdated
billing_statement.deletedBillingStatementDeleted
billing_statement.finalizedBillingStatementFinalized
billing_statement.sentBillingStatementSent
billing_statement.marked_uncollectibleBillingStatementMarkedUncollectible
billing_statement.voidedBillingStatementVoided
billing_statement.paidBillingStatementPaid
billing_statement.will_be_dueBillingStatementWillBeDue
billing_statement.overdueBillingStatementOverdue
billing_statement_line_item.createdBillingStatementLineItemCreated
billing_statement_line_item.updatedBillingStatementLineItemUpdated
billing_statement_line_item.deletedBillingStatementLineItemDeleted

All typed events extend PayrexWebhookEvent.

Listen for every verified type

Use the generic event for audit logging or a PayRex type the installed package does not map yet:

use ByRcsc\LaravelPayrex\Events\PayrexWebhookReceived;

final class RecordPayrexEvent implements ShouldQueue
{
    public function handle(PayrexWebhookReceived $event): void
    {
        $event->type();
        $event->event->id;
        $event->event->type;
        $event->event->raw;
    }
}

The generic event fires even when a typed event fires.

Inspect the event envelope

$event->event is a readonly WebhookEvent:

$webhook = $event->event;

$webhook->id;
$webhook->type;
$webhook->livemode;
$webhook->pendingWebhooks;
$webhook->previousAttributes;
$webhook->resourceType();
$webhook->resourceData();
$webhook->resource();
$webhook->raw;

resource() hydrates a supported subject into PaymentIntent, Payment, PaymentMethod, Refund, CheckoutSession, SetupIntent, Customer, BillingStatement, BillingStatementLineItem, or Payout. It returns null for an unknown resource; the raw data remains available.

Convenience methods exist for common subjects:

$webhook->paymentIntent();
$webhook->payment();
$webhook->refund();
$webhook->checkoutSession();

Use resource() plus instanceof for the other resource types.

Match event types

is() accepts exact names and a trailing wildcard:

if ($webhook->is('refund.created', 'refund.updated')) {
    // ...
}

if ($webhook->is('billing_statement.*')) {
    // ...
}

Customize the map

Add an event type by mapping it to a class that extends PayrexWebhookEvent:

use App\Events\CustomerUpdatedByPayrex;

'events' => [
    // package defaults...
    'customer.updated' => CustomerUpdatedByPayrex::class,
],
namespace App\Events;

use ByRcsc\LaravelPayrex\Events\PayrexWebhookEvent;

final class CustomerUpdatedByPayrex extends PayrexWebhookEvent
{
}

The package validates this map during application boot. Keys must be non-empty strings and classes must extend PayrexWebhookEvent.

Idempotency

PayRex may deliver an event more than once. A listener should claim the event ID before performing one-time work:

if (! PayrexDelivery::query()->firstOrCreate([
    'event_id' => $event->event->id,
])->wasRecentlyCreated) {
    return;
}

// Perform the state transition once.

Back the event ID with a unique database index so two queue workers cannot claim it simultaneously. Also make the domain update itself conditional; this protects against retries that happen after the claim but before work finishes.

Laravel PayRex is an unofficial community SDK and is not affiliated with PayRex.

View source