Platform events reference
Joryio emits these events automatically as part of the platform (message pipeline, wallet passes, store integrations, SDK). They appear in your event stream alongside your own custom events - this page is the canonical reference for what each one means. The AI Assistant knows these definitions and uses the signals when suggesting journeys and segments. For your own events and attributes, add descriptions on the Events and Attributes pages - the AI reads those too.
Messaging
| Event | Description | Signal |
|---|---|---|
message.sent | Joryio sent a message (any channel) to this user. | - |
message.delivered | Provider confirmed delivery. | - |
message.opened | Recipient opened an email. | engagement |
message.clicked | Recipient clicked a tracked link. | strong engagement |
message.bounced | Delivery bounced (hard/soft). | list-hygiene problem |
message.auto_replied | The recipient's mailbox sent an automatic reply (out of office). The email was delivered: not a bounce. | - |
message.unsubscribed | Recipient unsubscribed via a Joryio link or header, a preference-page save, or a STOP reply. scope says what they left: channel (only the channel the message came on), list, or global (everything - an explicit choice). Carries campaignId, canvasId, nodeId, variantId. unsubscribeSource says how it arrived (header_one_click = the mail app's button, page_button = the hosted page's button, preferences_page, page_everything, keyword; since 2026-10-15), with userAgent and sinceSendMs (ms after the send). Since 2026-11-02 it is also written when a team member (admin) or an API key (api) unsubscribes a channel, for an SDK unsubscribe (sdk) and for a store opt-out (store_sync, including an unticked box when the store's optional setting is on); these carry no campaign. | opt-out |
message.subscribed | A person became subscribed - the counterpart of message.unsubscribed (since 2026-10-25). Once per real change (from no status, unsubscribed or pending to subscribed), never when the person was already subscribed. scope: channel (the channel itself) or list (a list, with listId). Carries channel, source (how it happened - see The Subscribed event), platform for a store signup, optInSource, status, previousStatus, resubscribe. A journey can start on it. Not recorded for imports, warehouse syncs, bulk list adds or a store's initial sync. | opt-in |
Unsubscribe Page Viewed | Recipient opened the unsubscribe or preference page from a message link. Not an unsubscribe. Properties: campaignId, canvasId, nodeId, variantId, channel, page (unsubscribe or preferences), position (which unsubscribe link of the email). Bots excluded; once per link per 24 hours. | opt-out intent |
message.failed | Send failed at the provider. | - |
message.spam_complaint | Not an event name anything sends: spam complaints arrive as message.spamreport. Not offered in event pickers. | deliverability risk |
message.queued | Message accepted and queued at the provider. | - |
message.deferred | Provider temporarily deferred delivery (will retry). | - |
message.skipped | Send skipped by a Joryio gate (suppression, frequency cap, quiet hours, consent). | - |
message.held | Held by Joryio: the engagement gate held a journey message for a while because the person just received another one, or dropped it once stale; reason says why and names the competing message when there was one. | outcome, reason, nodeId |
message.complained | Accepted alias of message.spamreport when counting complaints (historical rows); no producer sends it today. Not offered in event pickers. | deliverability risk |
message.spamreport | Provider-reported spam complaint (alias of spam_complaint on some providers). | deliverability risk |
Wallet passes
| Event | Description | Signal |
|---|---|---|
pass.issued | A wallet pass was issued to the user (Joryio Wallet Passes). | - |
pass.installed | User added the pass to their Apple/Google wallet. | opt-in to the wallet channel |
pass.updated | A pass content update was pushed to installed passes. | - |
pass.removed | User REMOVED the pass from their wallet (Joryio Wallet Passes). | churn intent - a win-back play triggered on this is high-signal |
pass.downloaded | Pass file was downloaded (pre-install step). | - |
pass.scanned | Pass barcode/QR was scanned (e.g. redemption at the counter). | strong engagement - real-world usage |
pass.expired | Pass reached its expiry date. | renewal opportunity |
pass.update_pushed | A content update was pushed to installed passes (explicit push on edit). | - |
pass.voided | Pass was voided/deactivated by the business. | - |
E-commerce
| Event | Description | Signal |
|---|---|---|
purchase | Not an event Joryio sends: a completed purchase arrives as Order Completed. Not offered in event pickers. | - |
Order Completed | Completed order from a connected store, the Orders API or the SDK (canonical commerce event). Also carries the cart it came from and whether it won that cart back: cartRef, recoveredCart (true when it recovered an abandoned cart - the same decision as the Orders page's Recovered cart tag), recoveredVia (recovery_link, same_cart, contact_cart, reported), and the landing attribution the store reported: utm_source, utm_medium, utm_campaign, utm_term, utm_content, campaign_id, canvas_id. See Order Completed properties. | purchase - a recovered cart is the recovery journey's conversion |
Order Refunded | A connected store (Shopify, WooCommerce, Magento) or the Orders API reported a new refund on an order - one event per refund, full or partial. total is the amount this refund returned (total_base in the base currency), not the order total. Also: order_id, currency, refund_type (full or partial), refund_amount, refund_id, reason, products, coupon_codes. Revenue is already net of refunds, so this event never reduces it a second time. See Refund and cancellation events. | post-purchase dissatisfaction |
Order Cancelled | A connected store or the Orders API cancelled an order - once per order. Properties: order_id, total, currency, reason, cancelled_at, coupon_codes. | lost sale |
Coupon Issued | A coupon program issued a code to the person (properties: program, program_id, campaign_id, canvas_id, node_id, source, expires_at). The code itself is never on an event. | - |
Coupon Redeemed | An order used a code Joryio issued (adds order_id, revenue, redeemed_by_someone_else). Emitted on the person the code was issued to. | conversion from a message |
Coupon Expired | A code expired unused (program, program_id, campaign_id, canvas_id, expires_at). | win-back opportunity |
Checkout Started | Checkout began but is not yet completed. | - |
cart_abandoned | Not an event: the cart-abandoned STATE a segment or Branch condition checks (E-commerce: cart abandoned). To start a journey when a cart is abandoned, use Cart Abandoned. Not offered in event pickers, and a journey triggered on it cannot be published. | - |
Cart Abandoned | Sent by connected stores (Shopify, WooCommerce, Magento, PrestaShop) when a cart has been left without an order for the workspace's abandonment delay. checkoutUrl is the store's recovery link for this cart - link it as {{ cart.checkoutUrl }}. Shown in event pickers as "sent by connected stores". cartId identifies this cart: the contact's next cart gets a new one (before 2026-10-27 it repeated across a contact's carts). cartRef is the store's own reference of the cart (Magento quote_33, a WooCommerce session, a PrestaShop cart id, a Shopify checkout token). Not sent for a cart nobody can reach (no email, phone, customer id or app identity) - sent once if that contact becomes reachable - and once per abandonment: a cart whose items changed after it was abandoned (emptied and refilled, items added or removed), or that comes back unchanged a day or more later, and is left again is a new abandonment with a new cartId (The same cart abandoned again); a repeat of the same abandonment is not sent again. value is the cart total the store sent (it can include shipping); subtotal is the items subtotal, before shipping and tax. recoveryLink is true when checkoutUrl is the store's recovery link and false when it is only the checkout or cart page (from 2026-11-01). source is plugin_event when the store reported the abandonment and cart_abandonment_scan when Joryio marked the cart itself (When the store does not report the abandonment). | the classic recovery-journey trigger |
Cart Updated | Items added/removed from the cart. | - |
Product Added | Product added to cart. | purchase intent |
back_in_stock | A product the user recently viewed or added to cart (but did not buy) came back in stock - emitted per user on an out-of-stock → in-stock catalog transition (Shopify + WooCommerce). | high-converting retail trigger |
price_drop | A recently viewed/carted (not bought) product dropped in price beyond the configured threshold - emitted per user on a price-down catalog transition. | high-converting retail trigger |
entity_back_in_stock | Default event from an Entity Relationship Alert (custom-catalog restock, new episode, …) - emitted per user when a watched field on a custom-entity record transitions. Alerts can be configured to emit a custom event name instead. | custom-catalog trigger |
Product Viewed | Product page viewed. | browse interest |
SDK / Web
| Event | Description | Signal |
|---|---|---|
session_start | Not the name the SDKs send: a session start arrives as Session Start. Not offered in event pickers. | - |
Page Viewed | Page viewed (web SDK). | - |
Screen Viewed | Screen viewed (iOS and Android SDKs). The mobile counterpart of Page Viewed; mobile SDKs never emit Page Viewed. | screen_name |
signup | Not an event Joryio sends: apps track their own sign-up event (for example Signed Up). Not offered in event pickers. | - |
In-app
| Event | Description | Signal |
|---|---|---|
in_app.served | Server-side marker: an in-app message was delivered to a device for display (one per serve). It holds a frequency-cap slot for two minutes until the device confirms the show; only in_app.displayed, the client-confirmed impression, counts toward the cap. | - |
in_app.viewed | Not the name the SDKs send: an in-app impression arrives as in_app.displayed. Not offered in event pickers. | - |
in_app.clicked | User clicked a CTA inside an in-app message. | engagement |
in_app.displayed | An in-app message was displayed (impression). | - |
in_app.dismissed | User closed the in-app message without acting. | - |
in_app.converted | User performed the in-app message goal action. | conversion |
In-App Form Submitted | A form inside an in-app message was submitted and written to this person: attributes, list subscriptions, tags (properties: campaignId, campaignName, variantId, fields, listsSubscribed, and the form's email, phone and phoneUpdated - see Form Submitted). | conversion |
Journeys
Written by the journey engine for every step a person reaches and leaves, on every node type. Recorded from the 2026-10-13 release on - journey runs before it have no step events. Journey bookkeeping: never counted as the person's own activity, never billable.
| Event | Description | Signal |
|---|---|---|
canvas.step.entered | The person reached a journey step (trigger, delay, branch, experiment, message, any node). One per visit; a message held back by quiet hours or a rate limit and retried is the same visit. Properties: canvasId, canvasVersion, nodeId, nodeType, executionId. | - |
canvas.step.left | The person left a journey step. outcome is what the step decided - the branch label, the experiment path id (or no_winner when the experiment ended without a winner and released its waiting group - the run then ends as completed), success / on_error for a webhook, did / timed_out / a group name for a behavior split, issued / not_issued, sent / skipped, elapsed for a delay, otherwise next. nextNodeId is where they went; it is empty when the journey ended at this step, and then exitReason says why (completed, exited, exit_criteria, restart, error). durationMs is the time spent in the step. | - |
Recommendations
| Event | Meaning | Signal |
|---|---|---|
recommendation.served | A recommendation model resolved items for this user in a sent message (properties: modelId, itemIds). | personalization impression |
Landing pages
| Event | Meaning | Signal |
|---|---|---|
Landing Page Viewed | A known person (arrived through a Joryio link carrying their token) opened a published landing page (properties: pageId, pageSlug, pageName, referrer, UTM values). | interest |
Landing Page Form Submitted | A landing page form was submitted and written to this person: attributes, list subscriptions, tags (properties: pageId, pageSlug, pageName, fields, listsSubscribed, referrer, UTM values, and the form's email, phone and phoneUpdated - see Form Submitted). | conversion |
Website forms
| Event | Meaning | Signal |
|---|---|---|
Form Submitted | A form on your own site was submitted and written to this person: a Contact Form 7 or Elementor Pro form on WordPress (through the Joryio plugin), or the contact form or another mapped form on PrestaShop (through the Joryio module). Recorded whether or not they consented to marketing (properties: source - cf7, elementor, prestashop_contact or prestashop_form, formId, formName, pageUrl, consentGiven, consentText - the wording of the consent box the person ticked, when the form sends it - listsSubscribed, listsPending for double opt-in lists awaiting confirmation, and the form's own email and phone, formatted the way the contact stores them, with phoneUpdated when the form's phone differed from the contact's: true when the contact now has it, false when the contact kept its own). A visitor's form only fills an empty email or phone; a signed-in store customer's form can update their own phone. email and phone are personal data: hidden from team members who cannot see personal data and erased with the person. The other submitted values are not on the event. | conversion |