Orange Collar Media
Orange Collar Media
DOCS
OCMLABS/MODULE-WEBHOOK · PAYLOAD TEMPLATES

Shape webhook payloads with Smarty templates, live variable previews, and Send Test

MAGENTO 2.4.7 - 2.4.8 PHP 8.2 - 8.4 LUMA + HYVÄ COMPOSER

Payload bodies and custom header values are rendered through a sandboxed Smarty 5 engine. Templates are stored in the database and compiled from strings - admin input is never written to disk as a template file.

Webhook edit form with payload template and the Available Template Variables panel

Available variables

Every template, on every event, can reference the universal meta.* variables:

  • {$meta.event} - the Magento event name that triggered this delivery
  • {$meta.store_id} / {$meta.store_code} - the store scope the event fired in
  • {$meta.triggered_at} - ISO-8601 timestamp of when the event fired (not when it was delivered)
  • {$meta.webhook_name} - the admin label of the subscription being delivered
  • {$meta.delivery_uid} - the UUID also sent as X-Webhook-Delivery-Id
  • {$meta.test} - true only when rendered via the admin “Send Test” button

Event-specific variables ($order, $customer, $product, …) are documented live in the form: the “Available Template Variables” panel always lists meta.*, and the Load Variables for Selected Event button fetches the real, current variable set for your chosen event - resolved from actual store data rather than a hand-maintained list, so it always matches what your templates will see.

The two JSON modifiers

ModifierBehaviorUse it for
jsonJSON-encodes a complete value, including its own quotes/bracketsDumping an entire value: {$order.items|json}
escape_jsonSame encoding, but strips the surrounding quotesEmbedding a scalar inside a "..." pair you wrote yourself: "email": "{$order.customer_email|escape_json}"

Getting these backwards is the most common template bug: {$foo|json} inside hand-written quotes produces double-quoted JSON, while {$foo|escape_json} outside quotes produces an unquoted string.

Beyond those two, only an allowlist of native PHP functions is available as modifiers: count, nl2br, strtolower, strtoupper, ucfirst, trim, number_format, sprintf, implode, json_encode, and date. Anything else is rejected by the sandbox at save time.

Worked example: the default Order Placed template

{
"event": "{$meta.event}",
"triggered_at": "{$meta.triggered_at}",
"order": {
"increment_id": "{$order.increment_id}",
"grand_total": {$order.grand_total|number_format:2:".":""},
"currency": "{$order.order_currency_code}",
"customer_email": "{$order.customer_email|escape_json}",
"items": [
{foreach $order.items as $item}
{
"sku": "{$item.sku|escape_json}",
"name": "{$item.name|escape_json}",
"qty": {$item.qty_ordered},
"row_total": {$item.row_total}
}{if !$item@last},{/if}
{/foreach}
]
}
}

Notice grand_total and qty_ordered are emitted unquoted (they are already numeric), while customer_email, sku, and name go through escape_json because they are free text sitting inside a "..." pair the template author wrote by hand.

Custom headers

Custom header values use the same template engine and modifiers, so a header value of {$meta.store_code} is valid. Headers are sent with every delivery of that webhook.

Send Test

The Send Test button renders the current form state (even unsaved) against sample data resolved from your real store, delivers it synchronously to your URL, and shows the result: HTTP code, duration, response excerpt, the rendered payload, and - when something fails - the exact error, including template compile errors with their line number. Test deliveries carry {$meta.test} = true and an X-Webhook-Test: 1 header so your receiver can distinguish them from real events.

Sandbox rules

Admin-authored templates run with no static class access, no PHP constants, no superglobals, and only the allowlisted modifiers above. A template that uses anything outside the sandbox fails validation at save time with the exact error and never reaches runtime.