Notifications
Overview
CartThrob can send automatic notifications when checkout, inventory, order status, or add-on events occur. Email notification bodies are standard ExpressionEngine templates, so EE global variables, tags, conditionals, embeds, and layouts are available in addition to the variables injected by CartThrob.
You can create multiple notifications for the same event and send them to different people. Template parsing and notification delivery normally happen during the request that triggered the event. Expensive channel queries or other slow tags in a notification template can therefore delay the customer’s request.
To configure a notification:
- Create an EE template containing the message body.
- In CartThrob’s Notifications settings, click Add Notification.
- Set the subject, From name, From email, To email, and optional Reply-to values.
- Select the EE template.
- Select the event that should trigger the notification.
- For an order-status notification, select the original and new statuses.
- Select HTML or Plain Text.
Installed example templates
When you install CartThrob’s store example template group from the control
panel, CartThrob creates these notification templates:
store/email_admin— completed-order email for the store administratorstore/email_customer— completed-order email for the customerstore/email_low_stock— short low-stock alertstore/email_status_change— short order-status-change alert
The default notification configuration refers to these paths. Installing the templates does not overwrite an existing template with the same name.
Address fields
The notification address settings have distinct jobs:
- From name and From email identify the sender.
- To email identifies the recipient. It may contain a parsed variable such
as
{customer_email}when the event supplies that value. - Reply-to name and Reply-to email control where replies are sent. If either reply-to value is empty, CartThrob falls back to the corresponding From value.
Test notifications with two different mailboxes so the visible sender, recipient, and reply destination can be checked independently. This also helps catch mail-provider policies that rewrite or reject the From address.
Template variables
The variables are not identical for every event. The tables under each event group list the data passed by that notification call. The built-in email delivery driver adds a small second group of variables to every email notification; those are listed separately below.
The same event variables are also parsed in the notification’s From, To,
Reply-to, and Subject settings. For example, {customer_email} can be used in
the To field for a payment event because payment events supply that variable.
Low-stock events do not supply customer details, so {customer_email} should
not be used for a low-stock recipient.
Variables available to every email notification
These values describe the configured email notification. They are usually more useful for diagnostics or shared email layouts than for the message itself.
| Variable | Output |
|---|---|
{from} |
Configured From email address after CartThrob’s customer-address replacement, when applicable. |
{from_name} |
Configured From name after CartThrob’s customer-name replacement, when applicable. |
{from_reply_to} |
Configured Reply-to email, or the From email when Reply-to is empty. |
{from_reply_to_name} |
Configured Reply-to name, or the From name when Reply-to name is empty. |
{to} |
Configured recipient value after CartThrob’s customer-address replacement, when applicable. |
{subject} |
Subject stored on the notification. Event variables in the actual outgoing subject are parsed separately. |
{message_template} |
EE template path selected for the notification, such as store/email_customer. |
{plaintext} |
1 for a Plain Text notification and an empty value for an HTML notification. |
For backward compatibility, the email parser also replaces ORDER_ID and
{order_id}. They contain the payment event’s order entry ID when one
was supplied; for non-order events they are empty. Prefer {order_id} in
new templates. That is the ExpressionEngine entry ID, not the invoice ID
contained in the title.
{customer_name} and {customer_email} are not universal variables. They
are included in payment events and in custom events that explicitly provide
them.
Using other template tags
A notification body is a normal EE template. It can use other ExpressionEngine and CartThrob tags, with notification variables passed into their parameters when useful. Variables produced by those tags are not notification variables and are not duplicated on this page; use the documentation for the tag itself.
See, for example:
The low-stock example
below demonstrates this pattern with ExpressionEngine’s channel:entries tag.
Notification event groups
Payment events
The following control-panel events share the same checkout-order payload:
- Successful Transaction (
completed) - Declined Transaction (
declined) - Failed Transaction (
failed) - Customer completing transaction offsite (
offsite) - Incomplete Transaction / processing (
processing) - Refund alert (
refunded) - Payment Expired (
expired) - Payment Canceled (
canceled) - Payment Pending (
pending)
Values can be empty when they do not apply to the selected gateway or event. For example, an offsite event may not have a transaction ID yet, and a tokenized payment may not have a card type or last four digits.
Processing notifications for payment review
With the CartThrob 10 payment-reconciliation update, the existing Incomplete Transaction / processing event can also report a payment that needs merchant reconciliation. No new email recipient or notification is configured automatically.
These additional values are supplied for a reconciliation notification:
| Variable | Meaning |
|---|---|
{payment_review} |
True for a payment requiring reconciliation. |
{payment_review_kind} |
confirmed means the provider confirms collection; unknown means capture outcome is unconfirmed. |
{transaction_id} |
The payment reference retained for investigation. |
{error_message} |
Customer-safe review explanation, including instructions not to pay again. |
{order_id} |
Saved order entry ID, when one exists. |
Check the review flag before using ordinary “awaiting your check” wording:
{if payment_review}
{if payment_review_kind == "confirmed"}
<p>Payment was received, but this order needs review.</p>
{if:else}
<p>The payment outcome needs verification.</p>
{/if}
<p>{error_message}</p>
<p>Payment reference: {transaction_id}</p>
{if:else}
<p>Your order is processing. Follow the payment instructions supplied by the store.</p>
{/if}
A reconciliation hold dispatches Processing notifications, not the completed transaction event. Sending or resending an email does not resolve the payment or fulfill the order. Review any custom notification plugins or status-change emails that assume Processing means payment is safely complete.
Reconciliation, Purchased Items, and later status changes
Ordinary Processing creates Purchased Item channel entries when Save Orders and Save Purchased Items are enabled and configured. The payment-review hold withholds new entries while preserving available saved order line items. A Processing email must not assume that Purchased Item entries or download entitlements exist merely because the order is listed in Order Manager.
Mark reconciled dispatches neither Processing nor Completed notifications and does not create the withheld entries. Order Manager’s status edits can send configured Status Change notifications, but an EE status change does not run CartThrob’s full successful-checkout flow. The explicit Resend completed-order email action sends a receipt; it does not finish that flow.
The payment_review variables above are provided to the hold’s Processing
notification. Do not assume they are also supplied to arbitrary status-change
notifications or manually resent receipts. Review those rules separately,
especially any rule that treats a status name as proof of collection.
Completed notifications after merchant acceptance
The paid-order completion workflow
dispatches configured Completed notifications after supported local fulfillment
steps finish. It supplies payment_review=false, clears payment_review_kind,
and adds these values to the recovered order/customer payload:
| Variable | Meaning |
|---|---|
{reconciliation_outcome} |
accepted or accepted_adjustment. |
{reconciliation_amount} |
Net amount the merchant verified and accepted. |
{reconciliation_currency} |
Original order currency for that amount. |
{reconciliation_reference} |
Merchant-entered verification or adjustment reference. |
{reconciliation_note} |
Merchant’s resolution note; consider whether it belongs in a customer-facing message. |
The order total remains the original total, so an adjustment-aware receipt may need to show the accepted amount separately. These values are supplied to the completion dispatch, not automatically to every later resent receipt or arbitrary status-change event. Order Manager retains the recorded resolution for review.
Inventory processing can also send configured low-stock notifications. The action does not send another Processing notification. Record-only outcomes send neither checkout event. Existing notification selection and logging/sending settings still apply; no recipient is created automatically. A notification exception leaves the last step visible for manual follow-up, and completion is not automatically retried. Check notification logs before resending a message.
Order identifiers and site context
| Variable | Output |
|---|---|
{entry_id}, {order_id} |
ExpressionEngine entry ID. Same source; same value in the normal saved-order flow. |
{title}, {invoice_number} |
Full order entry title. Same source; same value. The invoice ID is the number contained in that title (prefix and suffix wrap it). It can match the entry ID depending on Order/Invoice Numbers; it is not always the same. |
{order_number} |
Digits from the invoice ID contained in the title (on submitted_order_info only). |
{member_id} |
Customer’s EE member ID, or 0 for a guest. |
{author_id} |
Order author/member ID in subscription-update flows that explicitly set it. It is not present in every payment event. |
{group_id} |
Customer’s EE member group ID. |
{site_id} |
EE site ID for the checkout. |
{site_name} |
Configured EE site name. |
Totals
These are rounded numeric values from the checkout snapshot; they are not automatically formatted with a currency symbol.
| Variable | Output |
|---|---|
{subtotal} |
Item subtotal before tax, shipping, and order discount. |
{subtotal_plus_tax} |
Subtotal including applicable item tax. |
{shipping} |
Shipping amount before shipping tax. |
{shipping_plus_tax} |
Shipping amount including applicable tax. |
{tax} |
Total tax amount. |
{discount} |
Total cart/order discount. |
{total}, {total_cart} |
Final checkout total. These are aliases in the payment payload. |
{currency_code} |
Currency code supplied for the checkout, when present. |
{subtotal_plus_shipping} |
Subtotal plus shipping. Added by certain subscription-update flows; do not assume it is present for every payment event. |
{tax_rate} |
Effective tax rate. Added by certain subscription-update flows; do not assume it is present for every payment event. |
Customer and billing details
| Variable | Output |
|---|---|
{customer_name} |
Customer’s billing first and last names joined with a space. |
{customer_email}, {email_address} |
Customer’s email address. |
{customer_phone} |
Customer’s billing phone number. |
{customer_ip_address}, {ip_address} |
IP address recorded for the checkout. |
{billing_first_name}, {first_name} |
Billing first name. |
{billing_last_name}, {last_name} |
Billing last name. |
{billing_company}, {company} |
Billing company. |
{billing_address}, {address} |
First billing address line. |
{billing_address2}, {address2} |
Second billing address line. |
{billing_city}, {city} |
Billing city. |
{billing_state}, {state} |
Billing state, province, or region. |
{billing_zip}, {zip} |
Billing postal code. |
{billing_country}, {country} |
Billing country value stored with the customer. |
{billing_country_code}, {country_code} |
Billing country code stored with the customer. |
{full_billing_address} |
Billing street, city, state, and postal code combined as a multiline string. |
The shorter names are aliases of the corresponding billing_* values.
Shipping details
When Use billing information is enabled at checkout, the shipping values contain the corresponding billing values.
| Variable | Output |
|---|---|
{shipping_first_name} |
Shipping first name. |
{shipping_last_name} |
Shipping last name. |
{shipping_phone} |
Shipping phone number. |
{shipping_company} |
Shipping company. |
{shipping_address} |
First shipping address line. |
{shipping_address2} |
Second shipping address line. |
{shipping_city} |
Shipping city. |
{shipping_state} |
Shipping state, province, or region. |
{shipping_zip} |
Shipping postal code. |
{shipping_country} |
Shipping country value stored with the customer. |
{shipping_country_code} |
Shipping country code stored with the customer. |
{full_shipping_address} |
Shipping street, city, state, and postal code combined as a multiline string. |
Payment and checkout details
| Variable | Output |
|---|---|
{payment_gateway} |
Selected gateway class name without the leading Cartthrob_. |
{payment_gateway_method} |
Selected gateway method, when the gateway supports methods. |
{transaction_id} |
Legacy top-level transaction value. It can be empty even after the gateway returns a reference; use submitted_order_info when a resolved transaction ID is required. |
{card_type} |
Detected or submitted card brand, when available. |
{last_four_digits} |
Last four digits supplied during checkout, when available. |
{coupon_codes} |
Applied coupon codes joined with commas. |
{subscription_id} |
Related subscription ID, when the event belongs to a subscription flow. |
{create_user} |
Whether checkout requested member creation. |
{return} |
General return URL saved with the checkout. |
{authorized_redirect} |
Success redirect selected for the checkout. |
{processing_redirect} |
Processing redirect selected for the checkout. |
{declined_redirect} |
Declined-payment redirect selected for the checkout. |
{failed_redirect} |
Failed-payment redirect selected for the checkout. |
Custom checkout data
Scalar custom customer-information fields are merged into the payment payload
under their configured names. Cart custom data is available with a
custom_data: prefix:
{custom_data:your_key}
These names depend on the site’s customer-field and custom-data setup, so they cannot be listed globally.
Non-scalar and legacy payload values
The checkout payload also carries internal arrays named auth,
coupon_codes_array, purchased_items, subscription, and
subscription_options. They are not a stable set of directly printable
template variables: CartThrob removes associative non-row arrays before
parsing, and their shapes vary by checkout path. Use:
{coupon_codes}for a printable coupon list;submitted_order_infofor normalized authorization state, transaction ID, and error message;order_itemsfor saved purchased-item rows;- the CartThrob Subscriptions tags for subscription records.
Some subscription and rebill paths can also carry the legacy scalar keys
authorized, processing, declined, failed, and error_message. These
values are normally empty in the direct payment payload. Use
submitted_order_info rather than relying on them.
Items
The checkout snapshot includes an {items} variable pair:
{items}
{title} — {quantity} × {price}
{/items}
Each row can contain:
| Variable | Output |
|---|---|
{row_id} |
Cart row identifier. |
{entry_id}, {product_id} |
Product entry ID. |
{site_id} |
Product’s EE site ID. |
{title} |
Product/item title. |
{quantity} |
Quantity purchased. |
{price} |
Unit price after option-based pricing. |
{price_plus_tax} |
Unit price including applicable tax. |
{weight} |
Calculated item weight. |
{shipping} |
Item shipping amount calculated by CartThrob. |
{discount} |
Discount amount returned for the item. |
{no_tax} |
Whether the item is marked tax exempt. |
{no_shipping} |
Whether the item is marked as requiring no shipping. |
{class} |
Cart item class, such as product or package, when present. |
Rows can also contain the nested item_options, meta, discounts, and
sub_items collections, plus an internal parent_item link in some item
classes. These values are not a stable scalar template surface; their keys and
shapes depend on the product and installed fieldtypes. For saved-order line
items, formatted subtotals, package rows, and product channel fields, use the
order_items tag.
Sensitive payment values
Some checkout internals can temporarily include CVV2,
expiration_month, or expiration_year. Never output these values in a
notification, subject, log, or stored template. They are not a supported
notification-template API. CartThrob does not expose a full card-number
template variable.
Low-stock event
The Low stock warning (low_stock) event adds only these variables:
| Variable | Output |
|---|---|
{entry_id} |
Product entry ID whose inventory was reduced. |
{inventory} |
Remaining inventory after the purchase quantity was deducted. |
The event is sent when the resulting inventory is at or below the low-stock level configured in CartThrob’s product settings. It does not include customer or order variables.
Example: pass a notification variable to another tag
That is enough data to load the complete product entry with ExpressionEngine’s
channel:entries tag. This fuller low-stock template outputs the remaining
inventory alongside standard product fields:
<p><strong>Low stock warning:</strong> {inventory} remaining.</p>
{exp:channel:entries
entry_id="{entry_id}"
dynamic="no"
limit="1"
disable="categories|member_data|pagination"
}
<h2>{title}</h2>
<p>Product entry ID: {entry_id}</p>
<p>Product URL title: {url_title}</p>
{!-- Add site-specific product fields here, such as {product_sku}. --}
{/exp:channel:entries}
{entry_id} and {inventory} come from the low-stock event.
{title}, {url_title}, and any custom product field short names are parsed
by channel:entries. A channel parameter is not required because the entry ID
uniquely identifies the product.
Order-status-change event
The Order status has been changed (status_change) event adds these core
variables:
| Variable | Output |
|---|---|
{entry_id} |
Order entry ID that changed. |
{status} |
New EE order-entry status. |
{previous_status} |
Status before the change. |
{channel_id} |
Orders channel ID. |
{url_title} |
Order entry URL title, when included by the update path. |
Depending on whether the change was made through ExpressionEngine publishing,
CartThrob Order Manager, Channel Form, or custom code, the payload can also
contain entry metadata and saved order fields. Order Manager supplies channel
field short names and field_id_N aliases, but templates intended to work
across every update path should not depend on those optional values.
Other EE and CartThrob tags can retrieve the complete saved order by using
{entry_id} as a tag parameter. Refer to that tag’s documentation for the
variables it produces.
When both an original status and a new status are configured, CartThrob
matches the complete transition. A notification configured for
Backordered to Shipped does not run for a different starting status that
also ends at Shipped.
Custom application events
CartThrob add-ons can register additional event names. A custom event receives the variables that the add-on passes when it dispatches the event, plus the shared email variables listed above. There is no universal CartThrob payload for application events.
Add-on developers can see Using CartThrob’s Notification System for event registration and dispatch examples.
Reviewing notifications after an upgrade
CartThrob continues to normalize legacy notification keys so existing configurations can be read. Compatibility does not guarantee that an old notification still expresses the desired event, template, addresses, or status transition. After an upgrade, review every notification in the control panel and send test messages for successful, failed, and status-change cases used by the site.