Events

Craft Commerce provides a multitude of events for extending its functionality. Modules and plugins can register event listeners, typically in their init() methods, to modify Commerce’s behavior.

# Event Code Generator

Select an event for details and a code snippet, or check out the sections below for some use cases. See Craft’s Events page for more information about working with events.

# Common Events + Workflows

The following sections highlight a few of the events emitted by Commerce classes. It is not exhaustive—meaning you may need to enlist the help of one or more development tools to aid in discovering the “right” event!

# Product + Variant Events

Products and variants are elements, so all the standard lifecycle events (for elements and their associated query classes) apply here.

# beforeCaptureVariantSnapshot

The event that is triggered before a variant’s field data is captured, which makes it possible to customize which fields are included in the snapshot. Custom fields are not included by default.

This example adds every custom field to the variant snapshot:

use craft\commerce\elements\Variant;
use craft\commerce\events\CustomizeVariantSnapshotFieldsEvent;
use yii\base\Event;

Event::on(
    Variant::class,
    Variant::EVENT_BEFORE_CAPTURE_VARIANT_SNAPSHOT,
    function(CustomizeVariantSnapshotFieldsEvent $event) {
        // @var Variant $variant
        $variant = $event->variant;
        // @var string[]|null $fields
        $fields = $event->fields;

        // Add every custom field to the snapshot
        if (($fieldLayout = $variant->getFieldLayout()) !== null) {
            foreach ($fieldLayout->getCustomFields() as $field) {
                $fields[] = $field->handle;
            }
        }

        $event->fields = $fields;
    }
);

Add with care! A huge amount of custom fields/data will increase your database size.

# afterCaptureVariantSnapshot

The event that is triggered after a variant’s field data is captured. This makes it possible to customize, extend, or redact the data to be persisted on the variant instance.

use craft\commerce\elements\Variant;
use craft\commerce\events\CustomizeVariantSnapshotDataEvent;
use yii\base\Event;

Event::on(
    Variant::class,
    Variant::EVENT_AFTER_CAPTURE_VARIANT_SNAPSHOT,
    function(CustomizeVariantSnapshotDataEvent $event) {
        // @var Variant $variant
        $variant = $event->variant;
        // @var array $data
        $data = $event->fieldData;

        // Modify or redact captured `$data`
        // ...
    }
);

# beforeCaptureProductSnapshot

The event that is triggered before a product’s field data is captured. This makes it possible to customize which fields are included in the snapshot. Custom fields are not included by default.

This example adds every custom field to the product snapshot:

use craft\commerce\elements\Variant;
use craft\commerce\elements\Product;
use craft\commerce\events\CustomizeProductSnapshotFieldsEvent;
use yii\base\Event;

Event::on(
    Variant::class,
    Variant::EVENT_BEFORE_CAPTURE_PRODUCT_SNAPSHOT,
    function(CustomizeProductSnapshotFieldsEvent $event) {
        // @var Product $product
        $product = $event->product;
        // @var array|null $fields
        $fields = $event->fields;

        // Add every custom field to the snapshot
        if (($fieldLayout = $product->getFieldLayout()) !== null) {
            foreach ($fieldLayout->getCustomFields() as $field) {
                $fields[] = $field->handle;
            }
        }

        $event->fields = $fields;
    }
);

Add with care! A huge amount of custom fields/data will increase your database size.

# afterCaptureProductSnapshot

The event that is triggered after a product’s field data is captured, which can be used to customize, extend, or redact the data to be persisted on the product instance.

use craft\commerce\elements\Variant;
use craft\commerce\elements\Product;
use craft\commerce\events\CustomizeProductSnapshotDataEvent;
use yii\base\Event;

Event::on(
    Variant::class,
    Variant::EVENT_AFTER_CAPTURE_PRODUCT_SNAPSHOT,
    function(CustomizeProductSnapshotDataEvent $event) {
        // @var Product $product
        $product = $event->product;
        // @var array $data
        $data = $event->fieldData;

        // Modify or redact captured `$data`
        // ...
    }
);

# Sale Events

# beforeMatchPurchasableSale

The event that is triggered before Commerce attempts to match a sale to a purchasable.

The isValid event property can be set to false to prevent the application of the matched sale.

use craft\commerce\events\SaleMatchEvent;
use craft\commerce\services\Sales;
use craft\commerce\base\PurchasableInterface;
use craft\commerce\models\Sale;
use yii\base\Event;

Event::on(
    Sales::class,
    Sales::EVENT_BEFORE_MATCH_PURCHASABLE_SALE,
    function(SaleMatchEvent $event) {
        // @var Sale $sale
        $sale = $event->sale;
        // @var PurchasableInterface $purchasable
        $purchasable = $event->purchasable;
        // @var bool $isNew
        $isNew = $event->isNew;

        // Use custom business logic to exclude purchasable from sale
        // with `$event->isValid = false`
        // ...
    }
);

# beforeSaveSale

The event that is triggered before a sale is saved.

use craft\commerce\events\SaleEvent;
use craft\commerce\services\Sales;
use craft\commerce\models\Sale;
use yii\base\Event;

Event::on(
    Sales::class,
    Sales::EVENT_BEFORE_SAVE_SALE,
    function(SaleEvent $event) {
        // @var Sale $sale
        $sale = $event->sale;
        // @var bool $isNew
        $isNew = $event->isNew;
        // ...
    }
);

# afterSaveSale

The event that is triggered after a sale is saved.

use craft\commerce\events\SaleEvent;
use craft\commerce\services\Sales;
use craft\commerce\models\Sale;
use yii\base\Event;

Event::on(
    Sales::class,
    Sales::EVENT_BEFORE_SAVE_SALE,
    function(SaleEvent $event) {
        // @var Sale $sale
        $sale = $event->sale;
        // @var bool $isNew
        $isNew = $event->isNew;
        // ...
    }
);

# afterDeleteSale

The event that is triggered after a sale is deleted.

use craft\commerce\events\SaleEvent;
use craft\commerce\services\Sales;
use craft\commerce\models\Sale;
use yii\base\Event;

Event::on(
    Sales::class,
    Sales::EVENT_AFTER_DELETE_SALE,
    function(SaleEvent $event) {
        // @var Sale $sale
        $sale = $event->sale;

        // do something
        // ...
    }
);

# Order Events

# beforeAddLineItemToOrder

The event that is triggered before a new line item has been added to the order.

use craft\commerce\elements\Order;
use craft\commerce\models\LineItem;
use craft\commerce\events\AddLineItemEvent;
use yii\base\Event;

Event::on(
    Order::class,
    Order::EVENT_BEFORE_ADD_LINE_ITEM,
    function(AddLineItemEvent $event) {
        // @var LineItem $lineItem
        $lineItem = $event->lineItem;
        // @var bool $isNew
        $isNew = $event->isNew;
        // @var bool $isValid
        $isValid = $event->isValid;
        // ...
    }
);

# afterAddLineItemToOrder

The event that is triggered after a line item has been added to an order.

use craft\commerce\elements\Order;
use craft\commerce\events\LineItemEvent;
use craft\commerce\models\LineItem;
use yii\base\Event;

Event::on(
    Order::class,
    Order::EVENT_AFTER_ADD_LINE_ITEM,
    function(LineItemEvent $event) {
        // @var LineItem $lineItem
        $lineItem = $event->lineItem;
        // @var bool $isNew
        $isNew = $event->isNew;
        // ...
    }
);

# afterApplyAddLineItemToOrder

The event that is triggered after a line item has been added to an order.

use craft\commerce\elements\Order;
use craft\commerce\events\LineItemEvent;
use craft\commerce\models\LineItem;
use yii\base\Event;
Event::on(
    Order::class,
    Order::EVENT_AFTER_APPLY_ADD_LINE_ITEM,
    function(LineItemEvent $event) {
        // @var LineItem $lineItem
        $lineItem = $event->lineItem;
        // @var bool $isNew
        $isNew = $event->isNew;
        // ...
    }
);

# afterRemoveLineItemToOrder

The event that is triggered after a line item has been removed from an order.

use craft\commerce\elements\Order;
use craft\commerce\events\LineItemEvent;
use craft\commerce\models\LineItem;
use yii\base\Event;

Event::on(
    Order::class,
    Order::EVENT_AFTER_REMOVE_LINE_ITEM,
    function(LineItemEvent $event) {
        // @var LineItem $lineItem
        $lineItem = $event->lineItem;
        // @var bool $isNew
        $isNew = $event->isNew;
        // ...
    }
);

# afterApplyRemoveLineItemFromOrder

The event that is triggered after a line item has been removed from an order.

use craft\commerce\elements\Order;
use craft\commerce\events\LineItemEvent;
use craft\commerce\models\LineItem;
use yii\base\Event;
Event::on(
    Order::class,
    Order::EVENT_AFTER_APPLY_REMOVE_LINE_ITEM,
    function(LineItemEvent $event) {
        // @var LineItem $lineItem
        $lineItem = $event->lineItem;
        // @var bool $isNew
        $isNew = $event->isNew;
        // ...
    }
);

# beforeCompleteOrder

The event that is triggered before an order is completed.

use craft\commerce\elements\Order;
use yii\base\Event;

Event::on(
    Order::class,
    Order::EVENT_BEFORE_COMPLETE_ORDER,
    function(Event $event) {
        // @var Order $order
        $order = $event->sender;
        // ...
    }
);

# afterCompleteOrder

The event that is triggered after an order is completed.

use craft\commerce\elements\Order;
use yii\base\Event;

Event::on(
    Order::class,
    Order::EVENT_AFTER_COMPLETE_ORDER,
    function(Event $event) {
        // @var Order $order
        $order = $event->sender;
        // ...
    }
);

# afterOrderAuthorized

This event is raised after an order is authorized in full and completed.

Plugins can get notified after an order is authorized in full and completed.

use craft\commerce\elements\Order;
use yii\base\Event;

Event::on(
    Order::class,
    Order::EVENT_AFTER_ORDER_AUTHORIZED,
    function(Event $event) {
        // @var Order $order
        $order = $event->sender;
        // ...
    }
);

# afterOrderPaid

The event that is triggered after an order is fully paid and completed.

use craft\commerce\elements\Order;
use yii\base\Event;

Event::on(
    Order::class,
    Order::EVENT_AFTER_ORDER_PAID,
    function(Event $event) {
        // @var Order $order
        $order = $event->sender;
        // ...
    }
);

# orderStatusChange

The event that is triggered when an order status is changed.

use craft\commerce\events\OrderStatusEvent;
use craft\commerce\services\OrderHistories;
use craft\commerce\models\OrderHistory;
use craft\commerce\elements\Order;
use yii\base\Event;

Event::on(
    OrderHistories::class,
    OrderHistories::EVENT_ORDER_STATUS_CHANGE,
    function(OrderStatusEvent $event) {
        // @var OrderHistory $orderHistory
        $orderHistory = $event->orderHistory;
        // @var Order $order
        $order = $event->order;

        // Let the delivery department know the order’s ready to be delivered
        // ...
    }
);

# defaultOrderStatus

The event that is triggered when a default order status is being fetched.

Set the event object’s orderStatus property to override the default status set in the control panel.

use craft\commerce\events\DefaultOrderStatusEvent;
use craft\commerce\services\OrderStatuses;
use craft\commerce\models\OrderStatus;
use craft\commerce\elements\Order;
use yii\base\Event;

Event::on(
    OrderStatuses::class,
    OrderStatuses::EVENT_DEFAULT_ORDER_STATUS,
    function(DefaultOrderStatusEvent $event) {
        // @var OrderStatus $status
        $status = $event->orderStatus;
        // @var Order $order
        $order = $event->order;

        // Choose a more appropriate order status than the control panel default
        // ...
    }
);

# registerOrderAdjusters

The event that is triggered for registration of additional adjusters.

use craft\events\RegisterComponentTypesEvent;
use craft\commerce\services\OrderAdjustments;
use yii\base\Event;

Event::on(
    OrderAdjustments::class,
    OrderAdjustments::EVENT_REGISTER_ORDER_ADJUSTERS,
    function(RegisterComponentTypesEvent $event) {
        $event->types[] = MyAdjuster::class;
    }
);

# modifyCartInfo

The event that’s triggered when a cart is returned as an array for Ajax cart update requests.

use craft\commerce\controllers\BaseFrontEndController;
use craft\commerce\events\ModifyCartInfoEvent;
use yii\base\Event;

Event::on(
    BaseFrontEndController::class,
    BaseFrontEndController::EVENT_MODIFY_CART_INFO,
    function(ModifyCartInfoEvent $e) {
        $cartArray = $e->cartInfo;
        $cartArray['anotherOne'] = 'Howdy';
        $e->cartInfo = $cartArray;
    }
);

# Discount Events

# afterDiscountAdjustmentsCreated

The event that is triggered after a discount has matched the order and before it returns its adjustments.

use craft\commerce\adjusters\Discount;
use craft\commerce\elements\Order;
use craft\commerce\models\Discount as DiscountModel;
use craft\commerce\models\OrderAdjustment;
use craft\commerce\events\DiscountAdjustmentsEvent;
use yii\base\Event;

Event::on(
    Discount::class,
    Discount::EVENT_AFTER_DISCOUNT_ADJUSTMENTS_CREATED,
    function(DiscountAdjustmentsEvent $event) {
        // @var Order $order
        $order = $event->order;
        // @var DiscountModel $discount
        $discount = $event->discount;
        // @var OrderAdjustment[] $adjustments
        $adjustments = $event->adjustments;

        // Use a third party to check order data and modify the adjustments
        // ...
    }
);

# beforeSaveDiscount

The event that is triggered before a discount is saved.

use craft\commerce\events\DiscountEvent;
use craft\commerce\services\Discounts;
use craft\commerce\models\Discount;
use yii\base\Event;

Event::on(
    Discounts::class,
    Discounts::EVENT_BEFORE_SAVE_DISCOUNT,
    function(DiscountEvent $event) {
        // @var Discount $discount
        $discount = $event->discount;
        // @var bool $isNew
        $isNew = $event->isNew;

        // Let an external CRM know about a client’s new discount
        // ...
    }
);

# afterSaveDiscount

The event that is triggered after a discount is saved.

use craft\commerce\events\DiscountEvent;
use craft\commerce\services\Discounts;
use craft\commerce\models\Discount;
use yii\base\Event;

Event::on(
    Discounts::class,
    Discounts::EVENT_AFTER_SAVE_DISCOUNT,
    function(DiscountEvent $event) {
        // @var Discount $discount
        $discount = $event->discount;
        // @var bool $isNew
        $isNew = $event->isNew;

        // Set this discount as default in an external CRM
        // ...
    }
);

# afterDeleteDiscount

The event that is triggered after a discount is deleted.

use craft\commerce\events\DiscountEvent;
use craft\commerce\services\Discounts;
use craft\commerce\models\Discount;
use yii\base\Event;

Event::on(
    Discounts::class,
    Discounts::EVENT_AFTER_DELETE_DISCOUNT,
    function(DiscountEvent $event) {
        // @var Discount $discount
        $discount = $event->discount;

        // Remove this discount from a payment gateway
        // ...
    }
);

# discountMatchesLineItem

The event that is triggered when a line item is matched with a discount.

This event will be raised if all standard conditions are met.

You may set the isValid property to false on the event to prevent the matching of the discount to the line item.

use craft\commerce\services\Discounts;
use craft\commerce\events\MatchLineItemEvent;
use craft\commerce\models\Discount;
use craft\commerce\models\LineItem;
use yii\base\Event;

Event::on(
    Discounts::class,
    Discounts::EVENT_DISCOUNT_MATCHES_LINE_ITEM,
    function(MatchLineItemEvent $event) {
        // @var LineItem $lineItem
        $lineItem = $event->lineItem;
        // @var Discount $discount
        $discount = $event->discount;

        // Check some business rules and prevent a match in special cases
        // ...
    }
);

# discountMatchesOrder

The event that is triggered when an order is matched with a discount.

You may set the isValid property to false on the event to prevent the matching of the discount with the order.

use craft\commerce\services\Discounts;
use craft\commerce\events\MatchOrderEvent;
use craft\commerce\models\Discount;
use craft\commerce\elements\Order;
use yii\base\Event;

Event::on(
    Discounts::class,
    Discounts::EVENT_DISCOUNT_MATCHES_ORDER,
    function(MatchOrderEvent $event) {
        // @var Order $order
        $order = $event->order;
        // @var Discount $discount
        $discount = $event->discount;

        // Check some business rules and prevent a match in special cases
        // ... $event->isValid = false; // set to false if you want it to NOT match as it would.
    }
);

# Line Item Events

# beforeSaveLineItem

The event that is triggered before a line item is saved.

use craft\commerce\events\LineItemEvent;
use craft\commerce\services\LineItems;
use craft\commerce\models\LineItem;
use yii\base\Event;

Event::on(
    LineItems::class,
    LineItems::EVENT_BEFORE_SAVE_LINE_ITEM,
    function(LineItemEvent $event) {
        // @var LineItem $lineItem
        $lineItem = $event->lineItem;
        // @var bool $isNew
        $isNew = $event->isNew;

        // Notify a third party service about changes to an order
        // ...
    }
);

# afterSaveLineItem

The event that is triggeredd after a line item is saved.

use craft\commerce\events\LineItemEvent;
use craft\commerce\services\LineItems;
use craft\commerce\models\LineItem;
use yii\base\Event;

Event::on(
    LineItems::class,
    LineItems::EVENT_AFTER_SAVE_LINE_ITEM,
    function(LineItemEvent $event) {
        // @var LineItem $lineItem
        $lineItem = $event->lineItem;
        // @var bool $isNew
        $isNew = $event->isNew;

        // Reserve stock
        // ...
    }
);

# populateLineItem

The event that is triggered as a line item is being populated from a purchasable.

use craft\commerce\events\LineItemEvent;
use craft\commerce\services\LineItems;
use craft\commerce\models\LineItem;
use yii\base\Event;

Event::on(
    LineItems::class,
    LineItems::EVENT_POPULATE_LINE_ITEM,
    function(LineItemEvent $event) {
        // @var LineItem $lineItem
        $lineItem = $event->lineItem;
        // @var bool $isNew
        $isNew = $event->isNew;

        // Modify the price of a line item
        // $lineItem->salePrice = 10;
        // $lineItem->price = 20;
        // ...
    }
);

Don’t forget to set salePrice accordingly since it’s the amount that gets added to the cart.

# createLineItem

The event that is triggered after a line item has been created from a purchasable.

use craft\commerce\events\LineItemEvent;
use craft\commerce\services\LineItems;
use craft\commerce\models\LineItem;
use yii\base\Event;

Event::on(
    LineItems::class,
    LineItems::EVENT_CREATE_LINE_ITEM,
    function(LineItemEvent $event) {
        // @var LineItem $lineItem
        $lineItem = $event->lineItem;
        // @var bool $isNew
        $isNew = $event->isNew;

        // Call a third party service based on the line item options
        // ...
    }
);

# defaultLineItemStatus

The event that is triggered when getting a default status for a line item.

You may set DefaultLineItemStatusEvent::lineItemStatus (opens new window) to a desired LineItemStatus to override the default status set in the control panel.

Plugins can get notified when a default line item status is being fetched.

use craft\commerce\services\LineItemStatuses;
use craft\commerce\events\DefaultLineItemStatusEvent;
use craft\commerce\models\LineItem;
use craft\commerce\models\LineItemStatus;
use yii\base\Event;

Event::on(
    LineItemStatuses::class,
    LineItemStatuses::EVENT_DEFAULT_LINE_ITEM_STATUS,
    function(DefaultLineItemStatusEvent $event) {
        // @var LineItem $lineItem
        $lineItem = $event->lineItem;
        // @var LineItemStatus $status
        $status = $event->lineItemStatus;

        // Specify a default line item status other than the CP selection
        // ...
    }
);

# Payment Events

# registerGatewayTypes

The event that is triggered for the registration of additional gateways.

This example registers a custom gateway instance of the MyGateway class:

use craft\events\RegisterComponentTypesEvent;
use craft\commerce\services\Purchasables;
use yii\base\Event;

Event::on(
    Gateways::class,
    Gateways::EVENT_REGISTER_GATEWAY_TYPES,
    function(RegisterComponentTypesEvent $event) {
        $event->types[] = MyGateway::class;
    }
);

# afterPaymentTransaction

The event that is triggered after a payment transaction is made.

use craft\commerce\events\TransactionEvent;
use craft\commerce\services\Payments;
use craft\commerce\models\Transaction;
use yii\base\Event;

Event::on(
    Payments::class,
    Payments::EVENT_AFTER_PAYMENT_TRANSACTION,
    function(TransactionEvent $event) {
        // @var Transaction $transaction
        $transaction = $event->transaction;

        // Check whether it was an authorize transaction
        // and make sure that warehouse team is on top of it
        // ...
    }
);

# beforeCaptureTransaction

The event that is triggered before a payment transaction is captured.

use craft\commerce\events\TransactionEvent;
use craft\commerce\services\Payments;
use craft\commerce\models\Transaction;
use yii\base\Event;

Event::on(
    Payments::class,
    Payments::EVENT_BEFORE_CAPTURE_TRANSACTION,
    function(TransactionEvent $event) {
        // @var Transaction $transaction
        $transaction = $event->transaction;

        // Check that shipment’s ready before capturing
        // ...
    }
);

# afterCaptureTransaction

The event that is triggered after a payment transaction is captured.

use craft\commerce\events\TransactionEvent;
use craft\commerce\services\Payments;
use craft\commerce\models\Transaction;
use yii\base\Event;

Event::on(
    Payments::class,
    Payments::EVENT_AFTER_CAPTURE_TRANSACTION,
    function(TransactionEvent $event) {
        // @var Transaction $transaction
        $transaction = $event->transaction;

        // Notify the warehouse we’re ready to ship
        // ...
    }
);

# beforeRefundTransaction

The event that is triggered before a transaction is refunded.

use craft\commerce\events\RefundTransactionEvent;
use craft\commerce\services\Payments;
use yii\base\Event;

Event::on(
    Payments::class,
    Payments::EVENT_BEFORE_REFUND_TRANSACTION,
    function(RefundTransactionEvent $event) {
        // @var float $amount
        $amount = $event->amount;

        // Do something else if the refund amount’s >50% of the transaction
        // ...
    }
);

# afterRefundTransaction

The event that is triggered after a transaction is refunded.

use craft\commerce\events\RefundTransactionEvent;
use craft\commerce\services\Payments;
use yii\base\Event;

Event::on(
    Payments::class,
    Payments::EVENT_AFTER_REFUND_TRANSACTION,
    function(RefundTransactionEvent $event) {
        // @var float $amount
        $amount = $event->amount;

        // Do something else if the refund amount’s >50% of the transaction
        // ...
    }
);

# beforeProcessPaymentEvent

The event that is triggered before a payment is processed.

You may set the isValid property to false on the event to prevent the payment from being processed.

use craft\commerce\events\ProcessPaymentEvent;
use craft\commerce\services\Payments;
use craft\commerce\elements\Order;
use craft\commerce\models\payments\BasePaymentForm;
use craft\commerce\models\Transaction;
use craft\commerce\base\RequestResponseInterface;
use yii\base\Event;

Event::on(
    Payments::class,
    Payments::EVENT_BEFORE_PROCESS_PAYMENT,
    function(ProcessPaymentEvent $event) {
        // @var Order $order
        $order = $event->order;
        // @var BasePaymentForm $form
        $form = $event->form;
        // @var Transaction $transaction
        $transaction = $event->transaction;
        // @var RequestResponseInterface $response
        $response = $event->response;

        // Check some business rules to see whether the transaction is allowed
        // ...
    }
);

# afterProcessPaymentEvent

The event that is triggered after a payment is processed.

use craft\commerce\events\ProcessPaymentEvent;
use craft\commerce\services\Payments;
use craft\commerce\elements\Order;
use craft\commerce\models\payments\BasePaymentForm;
use craft\commerce\models\Transaction;
use craft\commerce\base\RequestResponseInterface;
use yii\base\Event;

Event::on(
    Payments::class,
    Payments::EVENT_AFTER_PROCESS_PAYMENT,
    function(ProcessPaymentEvent $event) {
        // @var Order $order
        $order = $event->order;
        // @var BasePaymentForm $form
        $form = $event->form;
        // @var Transaction $transaction
        $transaction = $event->transaction;
        // @var RequestResponseInterface $response
        $response = $event->response;

        // Let the accounting department know an order transaction went through
        // ...
    }
);

# deletePaymentSource

The event that is triggered when a payment source is deleted.

use craft\commerce\events\PaymentSourceEvent;
use craft\commerce\services\PaymentSources;
use craft\commerce\models\PaymentSource;
use yii\base\Event;

Event::on(
    PaymentSources::class,
    PaymentSources::EVENT_DELETE_PAYMENT_SOURCE,
    function(PaymentSourceEvent $event) {
        // @var PaymentSource $source
        $source = $event->paymentSource;

        // Warn a user they don’t have any valid payment sources saved
        // ...
    }
);

# beforeSavePaymentSource

The event that is triggered before a payment source is added.

use craft\commerce\events\PaymentSourceEvent;
use craft\commerce\services\PaymentSources;
use craft\commerce\models\PaymentSource;
use yii\base\Event;

Event::on(
    PaymentSources::class,
    PaymentSources::EVENT_BEFORE_SAVE_PAYMENT_SOURCE,
    function(PaymentSourceEvent $event) {
        // @var PaymentSource $source
        $source = $event->paymentSource;

        // ...
    }
);

# afterSavePaymentSource

The event that is triggered after a payment source is added.

use craft\commerce\events\PaymentSourceEvent;
use craft\commerce\services\PaymentSources;
use craft\commerce\models\PaymentSource;
use yii\base\Event;

Event::on(
    PaymentSources::class,
    PaymentSources::EVENT_AFTER_SAVE_PAYMENT_SOURCE,
    function(PaymentSourceEvent $event) {
        // @var PaymentSource $source
        $source = $event->paymentSource;

        // Settle any outstanding balance
        // ...
    }
);

# afterSaveTransaction

The event that is triggered after a transaction has been saved.

use craft\commerce\events\TransactionEvent;
use craft\commerce\services\Transactions;
use craft\commerce\models\Transaction;
use yii\base\Event;

Event::on(
    Transactions::class,
    Transactions::EVENT_AFTER_SAVE_TRANSACTION,
    function(TransactionEvent $event) {
        // @var Transaction $transaction
        $transaction = $event->transaction;

        // Run custom logic for failed transactions
        // ...
    }
);

# afterCreateTransaction

The event that is triggered after a transaction has been created.

use craft\commerce\events\TransactionEvent;
use craft\commerce\services\Transactions;
use craft\commerce\models\Transaction;
use yii\base\Event;

Event::on(
    Transactions::class,
    Transactions::EVENT_AFTER_CREATE_TRANSACTION,
    function(TransactionEvent $event) {
        // @var Transaction $transaction
        $transaction = $event->transaction;

        // Run custom logic depending on the transaction type
        // ...
    }
);

# Subscription Events

# afterExpireSubscription

The event that is triggered after a subscription has expired.

use craft\commerce\events\SubscriptionEvent;
use craft\commerce\services\Subscriptions;
use craft\commerce\elements\Subscription;
use yii\base\Event;

Event::on(
    Subscriptions::class,
    Subscriptions::EVENT_AFTER_EXPIRE_SUBSCRIPTION,
    function(SubscriptionEvent $event) {
        // @var Subscription $subscription
        $subscription = $event->subscription;

        // Make a call to third party service to de-authorize a user
        // ...
    }
);

# beforeCreateSubscription

The event that is triggered before a subscription is created.

You may set the isValid property to false on the event to prevent the user from being subscribed to the plan.

use craft\commerce\events\CreateSubscriptionEvent;
use craft\commerce\services\Subscriptions;
use craft\elements\User;
use craft\commerce\base\Plan;
use craft\commerce\models\subscriptions\SubscriptionForm;
use yii\base\Event;

Event::on(
    Subscriptions::class,
    Subscriptions::EVENT_BEFORE_CREATE_SUBSCRIPTION,
    function(CreateSubscriptionEvent $event) {
        // @var User $user
        $user = $event->user;
        // @var Plan $plan
        $plan = $event->plan;
        // @var SubscriptionForm $params
        $params = $event->parameters;

        // Set the trial days based on some business logic
        // ...
    }
);

# afterCreateSubscription

The event that is triggered after a subscription is created.

use craft\commerce\events\SubscriptionEvent;
use craft\commerce\services\Subscriptions;
use craft\commerce\elements\Subscription;
use yii\base\Event;

Event::on(
    Subscriptions::class,
    Subscriptions::EVENT_AFTER_CREATE_SUBSCRIPTION,
    function(SubscriptionEvent $event) {
        // @var Subscription $subscription
        $subscription = $event->subscription;

        // Ignore suspended subscriptions
        if ($subscription->isSuspended) {
            return;
        }

        // Call a third party service to authorize a user
        // ...
    }
);

Since a subscription may be suspended at creation due to payment issues, you may want to check subscription properties like hasStarted or isSuspended before taking further action.

# beforeReactivateSubscription

The event that is triggered before a subscription gets reactivated.

You may set the isValid property to false on the event to prevent the subscription from being reactivated.

use craft\commerce\events\SubscriptionEvent;
use craft\commerce\services\Subscriptions;
use craft\commerce\elements\Subscription;
use yii\base\Event;

Event::on(
    Subscriptions::class,
    Subscriptions::EVENT_BEFORE_REACTIVATE_SUBSCRIPTION,
    function(SubscriptionEvent $event) {
        // @var Subscription $subscription
        $subscription = $event->subscription;

        // Use business logic to determine whether the user can reactivate
        // ...
    }
);

# afterReactivateSubscription

The event that is triggered after a subscription gets reactivated.

use craft\commerce\events\SubscriptionEvent;
use craft\commerce\services\Subscriptions;
use craft\commerce\elements\Subscription;
use yii\base\Event;

Event::on(
    Subscriptions::class,
    Subscriptions::EVENT_AFTER_REACTIVATE_SUBSCRIPTION,
    function(SubscriptionEvent $event) {
        // @var Subscription $subscription
        $subscription = $event->subscription;

        // Re-authorize the user with a third-party service
        // ...
    }
);

# beforeSwitchSubscriptionPlan

The event that is triggered before a subscription is switched to a different plan.

You may set the isValid property to false on the event to prevent the switch from happening.

use craft\commerce\events\SubscriptionSwitchPlansEvent;
use craft\commerce\services\Subscriptions;
use craft\commerce\base\Plan;
use craft\commerce\elements\Subscription;
use craft\commerce\models\subscriptions\SwitchPlansForm;
use yii\base\Event;

Event::on(
    Subscriptions::class,
    Subscriptions::EVENT_BEFORE_SWITCH_SUBSCRIPTION_PLAN,
    function(SubscriptionSwitchPlansEvent $event) {
        // @var Subscription $subscription
        $subscription = $event->subscription;
        // @var Plan $oldPlan
        $oldPlan = $event->oldPlan;
        // @var Plan $newPlan
        $newPlan = $event->newPlan;
        // @var SwitchPlansForm $params
        $params = $event->parameters;

        // Modify the switch parameters based on some business logic
        // ...
    }
);

# afterSwitchSubscriptionPlan

The event that is triggered after a subscription gets switched to a different plan.

use craft\commerce\events\SubscriptionSwitchPlansEvent;
use craft\commerce\services\Subscriptions;
use craft\commerce\base\Plan;
use craft\commerce\elements\Subscription;
use craft\commerce\models\subscriptions\SwitchPlansForm;
use yii\base\Event;

Event::on(
    Subscriptions::class,
    Subscriptions::EVENT_AFTER_SWITCH_SUBSCRIPTION_PLAN,
    function(SubscriptionSwitchPlansEvent $event) {
        // @var Subscription $subscription
        $subscription = $event->subscription;
        // @var Plan $oldPlan
        $oldPlan = $event->oldPlan;
        // @var Plan $newPlan
        $newPlan = $event->newPlan;
        // @var SwitchPlansForm $params
        $params = $event->parameters;

        // Adjust the user’s permissions on a third party service
        // ...
    }
);

# beforeCancelSubscription

The event that is triggered before a subscription is canceled.

You may set the isValid property to false on the event to prevent the subscription from being canceled.

use craft\commerce\events\CancelSubscriptionEvent;
use craft\commerce\services\Subscriptions;
use craft\commerce\elements\Subscription;
use craft\commerce\models\subscriptions\CancelSubscriptionForm;
use yii\base\Event;

Event::on(
    Subscriptions::class,
    Subscriptions::EVENT_BEFORE_CANCEL_SUBSCRIPTION,
    function(CancelSubscriptionEvent $event) {
        // @var Subscription $subscription
        $subscription = $event->subscription;
        // @var CancelSubscriptionForm $params
        $params = $event->parameters;

        // Check whether the user is permitted to cancel the subscription
        // ...
    }
);

# afterCancelSubscription

The event that is triggered after a subscription gets canceled.

use craft\commerce\events\CancelSubscriptionEvent;
use craft\commerce\services\Subscriptions;
use craft\commerce\elements\Subscription;
use craft\commerce\models\subscriptions\CancelSubscriptionForm;
use yii\base\Event;

Event::on(
    Subscriptions::class,
    Subscriptions::EVENT_AFTER_CANCEL_SUBSCRIPTION,
    function(CancelSubscriptionEvent $event) {
        // @var Subscription $subscription
        $subscription = $event->subscription;
        // @var CancelSubscriptionForm $params
        $params = $event->parameters;

        // Refund the user for the remainder of the subscription
        // ...
    }
);

# beforeUpdateSubscription

The event that is triggered before a subscription gets updated. Typically this event is fired when subscription data is updated on the gateway.

use craft\commerce\events\SubscriptionEvent;
use craft\commerce\services\Subscriptions;
use craft\commerce\elements\Subscription;
use yii\base\Event;

Event::on(
    Subscriptions::class,
    Subscriptions::EVENT_BEFORE_UPDATE_SUBSCRIPTION,
    function(SubscriptionEvent $event) {
        // @var Subscription $subscription
        $subscription = $event->subscription;

        // ...
    }
);

# receiveSubscriptionPayment

The event that is triggered when a subscription payment is received.

use craft\commerce\events\SubscriptionPaymentEvent;
use craft\commerce\services\Subscriptions;
use craft\commerce\elements\Subscription;
use craft\commerce\models\subscriptions\SubscriptionPayment;
use DateTime;
use yii\base\Event;

Event::on(
    Subscriptions::class,
    Subscriptions::EVENT_RECEIVE_SUBSCRIPTION_PAYMENT,
    function(SubscriptionPaymentEvent $event) {
        // @var Subscription $subscription
        $subscription = $event->subscription;
        // @var SubscriptionPayment $payment
        $payment = $event->payment;
        // @var DateTime $until
        $until = $event->paidUntil;

        // Update loyalty reward data
        // ...
    }
);

# Mail Events

# beforeSendEmail

The event that is triggered before an email is sent out.

You may set the isValid property to false on the event to prevent the email from being sent.

use craft\commerce\events\MailEvent;
use craft\commerce\services\Emails;
use craft\commerce\elements\Order;
use craft\commerce\models\Email;
use craft\commerce\models\OrderHistory;
use craft\mail\Message;
use yii\base\Event;

Event::on(
    Emails::class,
    Emails::EVENT_BEFORE_SEND_MAIL,
    function(MailEvent $event) {
        // @var Message $message
        $message = $event->craftEmail;
        // @var Email $email
        $email = $event->commerceEmail;
        // @var Order $order
        $order = $event->order;
        // @var OrderHistory $history
        $history = $event->orderHistory;

        // Use `$event->isValid = false` to prevent sending
        // based on some business rules or client preferences
        // ...
    }
);

# afterSendEmail

The event that is triggered after an email has been sent out.

use craft\commerce\events\MailEvent;
use craft\commerce\services\Emails;
use craft\commerce\elements\Order;
use craft\commerce\models\Email;
use craft\commerce\models\OrderHistory;
use craft\mail\Message;
use yii\base\Event;

Event::on(
    Emails::class,
    Emails::EVENT_AFTER_SEND_MAIL,
    function(MailEvent $event) {
        // @var Message $message
        $message = $event->craftEmail;
        // @var Email $email
        $email = $event->commerceEmail;
        // @var Order $order
        $order = $event->order;
        // @var OrderHistory $history
        $history = $event->orderHistory;

        // Add the email address to an external CRM
        // ...
    }
);

# beforeSaveEmail

The event that is triggered before an email is saved.

use craft\commerce\events\EmailEvent;
use craft\commerce\services\Emails;
use craft\commerce\models\Email;
use yii\base\Event;

Event::on(
    Emails::class,
    Emails::EVENT_BEFORE_SAVE_EMAIL,
    function(EmailEvent $event) {
        // @var Email $email
        $email = $event->email;
        // @var bool $isNew
        $isNew = $event->isNew;

        // ...
    }
);

# afterSaveEmail

The event that is triggered after an email is saved.

use craft\commerce\events\EmailEvent;
use craft\commerce\services\Emails;
use craft\commerce\models\Email;
use yii\base\Event;

Event::on(
    Emails::class,
    Emails::EVENT_AFTER_SAVE_EMAIL,
    function(EmailEvent $event) {
        // @var Email $email
        $email = $event->email;
        // @var bool $isNew
        $isNew = $event->isNew;

        // ...
    }
);

# beforeDeleteEmail

The event that is triggered before an email is deleted.

use craft\commerce\events\EmailEvent;
use craft\commerce\services\Emails;
use craft\commerce\models\Email;
use yii\base\Event;

Event::on(
    Emails::class,
    Emails::EVENT_BEFORE_DELETE_EMAIL,
    function(EmailEvent $event) {
        // @var Email $email
        $email = $event->email;

        // ...
    }
);

# afterDeleteEmail

The event that is triggered after an email is deleted.

use craft\commerce\events\EmailEvent;
use craft\commerce\services\Emails;
use craft\commerce\models\Email;
use yii\base\Event;

Event::on(
    Emails::class,
    Emails::EVENT_AFTER_DELETE_EMAIL,
    function(EmailEvent $event) {
        // @var Email $email
        $email = $event->email;

        // ...
    }
);

# PDF Events

# beforeRenderPdf

The event that is triggered before an order’s PDF is rendered.

Event handlers can customize PDF rendering by modifying several properties on the event object:

Property Value
order populated Order (opens new window) model
template optional Twig template path (string) to be used for rendering
variables populated with the variables availble to the template used for rendering
option optional string for the template that can be used to show different details based on context (example: receipt, ajax)
pdf null by default, can optionally be used to supply your own PDF string rather than the one Commerce would generate
use craft\commerce\events\PdfRenderEvent;
use craft\commerce\services\Pdfs;
use yii\base\Event;

Event::on(
    Pdfs::class,
    Pdfs::EVENT_BEFORE_RENDER_PDF,
    function(PdfRenderEvent $event) {
        // Modify `$event->order`, `$event->option`, `$event->template`,
        // and `$event->variables` to customize what gets rendered into a PDF;
        // or render your own PDF and set its string on `$event->pdf`
        // ...
    }
);

If you provide your own PDF string, Commerce will skip its own rendering and afterRenderPdf will not be triggered.

# afterRenderPdf

The event that is triggered after an order’s PDF has been rendered by Commerce.

Event handlers can override Commerce’s PDF generation by setting the pdf property on the event to a custom-rendered PDF string. The event properties will be the same as those from beforeRenderPdf, but pdf will contain a rendered PDF string and is the only one for which setting a value will make any difference for the resulting PDF output.

use craft\commerce\events\PdfRenderEvent;
use craft\commerce\services\Pdfs;
use yii\base\Event;

Event::on(
    Pdfs::class,
    Pdfs::EVENT_AFTER_RENDER_PDF,
    function(PdfRenderEvent $event) {
        // Add a watermark to the PDF or forward it to the accounting department
        // ...
    }
);

# beforeSavePdf

The event that is triggered before a PDF’s configuration is saved.

use craft\commerce\events\PdfEvent;
use craft\commerce\services\Pdfs;
use craft\commerce\models\Pdf;
use yii\base\Event;

Event::on(
    Pdfs::class,
    Pdfs::EVENT_BEFORE_SAVE_PDF,
    function(PdfEvent $event) {
        // @var Pdf $pdf
        $pdf = $event->pdf;
        // @var bool $isNew
        $isNew = $event->isNew;
        // ...
    }
);

# afterSavePdf

The event that is triggered after a PDF’s configuration is saved.

use craft\commerce\events\PdfEvent;
use craft\commerce\services\Pdfs;
use craft\commerce\models\Pdf;
use yii\base\Event;

Event::on(
    Pdfs::class,
    Pdfs::EVENT_AFTER_SAVE_PDF,
    function(PdfEvent $event) {
        // @var Pdf $pdf
        $pdf = $event->pdf;
        // @var bool $isNew
        $isNew = $event->isNew;
        // ...
    }
);

# Product Types

# beforeSaveProductType

The event that is triggered before a product type is saved.

use craft\commerce\events\ProductTypeEvent;
use craft\commerce\services\ProductTypes;
use craft\commerce\models\ProductType;
use yii\base\Event;

Event::on(
    ProductTypes::class,
    ProductTypes::EVENT_BEFORE_SAVE_PRODUCTTYPE,
    function(ProductTypeEvent $event) {
        // @var ProductType|null $productType
        $productType = $event->productType;

        // Create an audit trail of this action
        // ...
    }
);

# afterSaveProductType

The event that is triggered after a product type has been saved.

use craft\commerce\events\ProductTypeEvent;
use craft\commerce\services\ProductTypes;
use craft\commerce\models\ProductType;
use yii\base\Event;

Event::on(
    ProductTypes::class,
    ProductTypes::EVENT_AFTER_SAVE_PRODUCTTYPE,
    function(ProductTypeEvent $event) {
        // @var ProductType|null $productType
        $productType = $event->productType;

        // Prepare some third party system for a new product type
        // ...
    }
);

# Purchasables

# registerPurchasableElementTypes

The event that is triggered for registration of additional purchasables.

This example adds an instance of MyPurchasable to the event object’s types array:

use craft\events\RegisterComponentTypesEvent;
use craft\commerce\services\Purchasables;
use yii\base\Event;

Event::on(
    Purchasables::class,
    Purchasables::EVENT_REGISTER_PURCHASABLE_ELEMENT_TYPES,
    function(RegisterComponentTypesEvent $event) {
        $event->types[] = MyPurchasable::class;
    }
);

# purchasableAvailable

The event that’s triggered when determining whether a purchasable should be available for a given current user and cart.

use craft\commerce\events\PurchasableAvailableEvent;
use craft\commerce\services\Purchasables;
use yii\base\Event;
Event::on(
    Purchasables::class,
    Purchasables::EVENT_PURCHASABLE_AVAILABLE,
    function(PurchasableAvailableEvent $event) {
        if ($order && $user = $order->getUser()){
            // Prevent users in group ID 1 from having the purchasable in their cart
            $event->isAvailable = $event->isAvailable && !$user->isInGroup(1);
        }
    }
);

If the purchasable becomes unavailable after being added to the cart, an order notice will be added to the order informing the customer.

# modifyPurchasablesTableQuery

The event that is triggered retrieving the list of purchasables for the add a line item feature on the order edit page.

This example adds a condition to the query to only return purchasables with a SKU that contains foo:

use craft\commerce\controllers\OrdersController;
use craft\commerce\events\ModifyPurchasablesTableQueryEvent;

Event::on(
    OrdersController::class,
    OrdersController::EVENT_MODIFY_PURCHASABLES_TABLE_QUERY,
    function(ModifyPurchasablesTableQueryEvent $event) {
        $likeOperator = Craft::$app->getDb()->getIsPgsql() ? 'ILIKE' : 'LIKE';
        $event->query->andWhere([$likeOperator, 'sku', 'foo']);
    }
);

# purchasableShippable

The event that is triggered when determining whether a purchasable may be shipped.

This example prevents the purchasable from being shippable in a specific user group’s orders:

use craft\commerce\events\PurchasableShippableEvent;
use craft\commerce\services\Purchasables;
use yii\base\Event;

Event::on(
    Purchasables::class,
    Purchasables::EVENT_PURCHASABLE_SHIPPABLE,
    function(PurchasableShippableEvent $event) {
        if ($order && $user = $order->getUser()){
            // Prevent users in group ID 1 from being able to ship this purchasable
            $event->isShippable = $event->is && !$user->isInGroup(1);
        }
    }
);

# Shipping

# registerAvailableShippingMethods

The event that is triggered for registration of additional shipping methods.

This example adds an instance of MyShippingMethod to the event object’s shippingMethods array:

use craft\commerce\events\RegisterAvailableShippingMethodsEvent;
use craft\commerce\services\ShippingMethods;
use yii\base\Event;

Event::on(
    ShippingMethods::class,
    ShippingMethods::EVENT_REGISTER_AVAILABLE_SHIPPING_METHODS,
    function(RegisterAvailableShippingMethodsEvent $event) {
        $event->shippingMethods[] = MyShippingMethod::class;
    }
);