Orders
The Orders page answers the question only Joryio can: which message produced each order. It is operational, not analytical - find an order, check its status, and see its attribution. Revenue analysis lives on the E-Commerce Overview; fulfilment (shipping, refunds) is managed in your store.
Every figure is net of refunds.
The page
- Header - title, a date-range picker (the same presets used across analytics), and Export CSV.
- Status tabs - All orders / Paid / Pending / Refunded, with counts.
- Toolbar - search (order number, customer name or email), source, customer, attribution, and sort.
- Table - one row per order; a row opens the detail drawer.
- Pagination - server-side; the page loads one page at a time.
Status tabs
The page uses a payment-oriented view of status - the store owns fulfilment, so a shipped or delivered order reads as Paid here once the store says it was paid (see Paid or awaiting payment):
| Tab | Includes |
|---|---|
| Paid | Payment received (processing, shipped, delivered) |
| Pending | Not paid yet: pending orders, and orders Awaiting payment (processing, shipped or delivered, but the store has not been paid - Cash on delivery, for example) |
| Refunded | Fully or partly refunded |
Paid or awaiting payment
An order's status says where it is (processing, shipped, delivered); whether it was paid is a separate fact, read from what each store records. A processing, shipped or delivered order the store has not been paid for shows an amber Awaiting payment badge and counts under Pending, never under Paid:
| Store | Paid when |
|---|---|
| WooCommerce | The order is Completed, or it was paid through a payment gateway. A Cash on delivery order, or one made in the admin without a payment method, is Awaiting payment until you mark it Completed - WooCommerce records a payment date on every order that reaches Processing, so that date alone is not read as payment. Bank transfer and cheque orders wait in On hold (Pending) until you move them to Processing, which marks them paid |
| Shopify | The order's payment status is Paid (or Refunded / Partially refunded). Pending, Authorized, Partially paid, Voided and Expired are not paid |
| Magento | The order's invoices are paid (the amount paid reaches the order total), or the order is Complete or Closed. An order Magento moved to Processing because it was shipped before it was invoiced is Awaiting payment |
| PrestaShop | The order's current state is marked "Set the order as paid" |
| Orders API | You send paymentStatus: unpaid (or paid). Without it, a processing, shipped or delivered order counts as paid |
Revenue is not affected: revenue and attribution count every order that is not cancelled or refunded, paid or not, as before.
Orders received before this change show what their status said until the store sends the order again (any update, the store reconciliation, or Sync now on the integration). Shopify orders already carry their payment status and show it straight away. WooCommerce needs plugin 1.6.20 or later for its live events to carry it (the REST sync and webhooks carry it with any version); Magento needs extension 1.4.20 or later (its order sync carries it with any version).
Toolbar filters
| Filter | Options |
|---|---|
| Search | Order number, customer name, or email |
| Attributed to | All / Campaigns only / Journeys only / Not attributed |
| Customer | All / First-time / Repeat |
| Attributed via | All / Coupon code / Click-through only / Assisted click / Opened only |
| Store | All stores, or one store (see Store and sales channel) |
| Channel | All channels / Online / Point of sale / App / Phone and manual / Marketplace / Other |
| Sort | Newest / Highest value / Lowest value |
Table columns
| Column | Description |
|---|---|
| Order | Your order number |
| Date | When it was placed |
| Customer | Name + FIRST/REPEAT badge + email |
| Items | First item + "+N more - N units" |
| Total | Order total, with "-$x refunded" beneath (struck through when fully refunded) |
| Attributed to | Campaign/journey + channel + how it was earned |
| Store and channel | The store the order belongs to, and where it was sold |
| Status | Paid / Awaiting payment / Pending / Partly refunded / Refunded |
Attribution
For each order, Joryio records which campaign or journey produced it, how the credit was earned, and when:
| How | Meaning | Strength |
|---|---|---|
| Click-through (direct) | The customer clicked this campaign's link and bought (deterministic, same session) | Strong |
| Assisted click | The customer clicked a message within the window before buying | Strong |
| Opened only | The customer opened but did not click (shown in amber) | Weak |
| Not attributed | No engagement within the window - still counts toward total revenue | - |
The "Attributed to" cell shows the campaign/journey name, a channel chip (email/SMS/push/in-app/WhatsApp), and a line like "clicked - 3h before" or "opened only - 41h before".
Click-through only
Some teams trust only purchases where the customer clicked a link and bought (deterministic), and want to exclude the windowed/assisted effect. Use the Attribution → Click-through only filter to list exactly those orders. The same view is available as a toggle on the E-Commerce Overview and as the Direct figure on a campaign's analytics.
Detail drawer
Opening an order shows the attribution first (why it is - or is not - credited), then the customer, then line items with subtotal, refunded amount, and net revenue. Refunds and fulfilment are managed in your store, and the drawer says so. A cancelled order shows net revenue 0 and says Cancelled - not counted in revenue, like every revenue figure that leaves it out.
Recovered cart
An order placed from an abandoned cart - that same cart, or a recovery link to it; an order the contact places from a new cart is not a recovery (see Carts) - carries a Recovered cart tag under "Attributed to", and its drawer opens with the cart it recovered: whose it was (another contact, when the buyer checked out from a recovery link under a different email), its value, when it was abandoned, and a View cart link to Carts.
Recovery and attribution are separate. Recovery says which cart the order came from; "Attributed to" says which message gets the credit - for a recovery, the message whose recovery link was clicked, also when the buyer checked out under another email (see Carts). A recovered order is "Not attributed" only when no click on a message was recorded.
Coupons
The drawer lists every coupon code the order used, with the discount each code gave, and the order's total discount. Every code is kept, not only the first:
| Store | Codes | Discount per code |
|---|---|---|
| WooCommerce | Every coupon line | Yes (excluding tax). Plugin orders carry it from plugin 1.3.1; older plugins send the codes only |
| Shopify | Every discount code | Yes, with its type (fixed amount, percentage, shipping) |
| Magento | The order's coupon code | No - Magento reports one discount for all of an order's cart rules, so the drawer shows "amount not reported by the store" and the order's total discount |
| Orders API | Every entry in coupons | When you send amount |
Codes are matched without regard to letter case - SUMMER10 and summer10 are one code. Build an audience with the coupon filters, or start a journey on Order Completed where coupon_codes contains the code (see coupon codes on the purchase event).
Store and sales channel
Every order shows where it was sold - its sales channel - and the store it belongs to, so a business with a shop and a website, or with two stores, can tell their orders apart. Filter the list with Store and Channel; the E-Commerce overview splits revenue the same way, and the store and channel filters build audiences from it.
| Channel | Meaning |
|---|---|
Online (online) | Your website or web checkout - the default |
Point of sale (pos) | A register in a physical shop |
App (app) | Your mobile app |
Phone and manual (phone) | Entered by staff: phone, email or manual orders, drafts |
Marketplace (marketplace) | A third-party marketplace |
Other (other) | Anything else |
A connected store is the store for its orders, and the channel comes from what the platform records: Shopify's order source (pos for Shopify POS, draft and admin-app orders as phone), WooCommerce's "created via" (admin orders as phone, a POS plugin as point of sale), and Magento admin-created orders as phone. PrestaShop does not record where an order was placed, so its orders are online. Orders sent through the API carry the salesChannel, storeId and storeName you send - see Store and sales channel in the API.
Export CSV
Export CSV downloads the orders the page currently shows - the same date range, tab, filters, search and sort - across every page, up to 50,000 orders (narrow the date range for more). Each row has the order, customer, totals, discount, attribution and two coupon columns: coupon_codes (SUMMER10; VIP) and coupons, which adds each code's discount when it is known (SUMMER10 (10.00); VIP). Exporting needs the export permission (users:export), because the file contains customer emails. The store, store_id and sales_channel columns say which store the order belongs to and where it was sold (channel is the attribution channel).
Attribution models and windows
How an order is credited is configurable:
- Model - Last touch (a click beats an open), Last click, or First touch. Set the workspace default under Settings → Revenue attribution; a campaign or journey can override it in its conversion settings.
- Window - how far back a touch may sit before the order. Each campaign/journey uses its own conversion window (default 7 days).
- Count opens - whether opens (weaker, noisier than clicks) attribute at all. Workspace-level, on by default.
Changing a setting applies to new orders immediately and re-credits existing orders in the background. To compare models side by side (e.g. last-click vs last-touch), open E-Commerce → Overview → Compare models.
Order fields
| Field | Description |
|---|---|
externalId | Your order ID from your e-commerce platform |
userId | Customer's Joryio user ID |
status | Order status |
paymentStatus | paid or unpaid, as the store reported it; empty when no store said (see Paid or awaiting payment) |
total | Final order amount |
subtotal | Amount before discounts |
totalRefunded | Amount refunded so far (nets revenue) |
items | Line items array |
coupons | Every coupon code on the order: code, amount (the discount it gave, when the store reports it) and type. couponCode still carries the first code |
placedAt | Order timestamp |
campaignId / canvasId | Deterministic (click-through) attribution tag |
source, utmSource, utmMedium, utmCampaign | Channel / UTM tags |
salesChannel, storeId | Where the order was sold (online, pos, app, phone, marketplace, other) and the store it belongs to - see Store and sales channel |
Line items carry product ID and name, quantity and price, SKU/variant, and image URL.
Using orders in campaigns
Order confirmation emails
<h1>Thank You for Your Order!</h1>
<p>Order #{{ order.id }}</p>
{% for item in order.items %}
<div class="item">
<img src="{{ item.imageUrl }}" />
<p>{{ item.name }} x {{ item.quantity }}</p>
<p>${{ item.price }}</p>
</div>
{% endfor %}
<p>Total: ${{ order.total }}</p>
Post-purchase flows
Create Canvas flows triggered by order events - order confirmation, delivery follow-up, review request, replenishment.
Order events
| Event | Trigger |
|---|---|
ecommerce.order.created | New order placed |
ecommerce.order.fulfilled | Order shipped |
ecommerce.order.cancelled | Order cancelled |
ecommerce.order.refunded | Refund processed |
ecommerce.order.status_changed | Any status change |
Order Completed properties
Besides the order itself (orderId, total, currency, itemCount, coupon_codes, source), every Order Completed event carries the cart the order came from and how the shopper arrived, so a segment filter or a journey condition can use them:
| Property | Type | Value |
|---|---|---|
cartRef | text | The store's reference of the cart the order was placed from (Magento quote_33, a WooCommerce session, a PrestaShop cart id, a Shopify checkout token) - the same cartRef that cart's Cart Abandoned carried. Only when the store sends it. |
recoveredCart | true / false | true when the order recovered an abandoned cart - the same decision as the Recovered cart tag. An order placed from a new cart is false. |
recoveredVia | text | Only on a recovery. recovery_link: a recovery link restored that cart. same_cart: the abandoned cart itself was checked out. contact_cart: the order carried no cart reference (Orders API, SDK and WooCommerce webhook orders), so the contact's own abandoned cart counted. reported: POST /carts/recovered named this order. |
utm_source, utm_medium, utm_campaign, utm_term, utm_content | text | The UTM parameters of the visit the order came from, when the store reports them (Shopify sends source, medium and campaign). |
campaign_id, canvas_id | text | The Joryio campaign or journey whose link the shopper arrived from, when the link carried one. |
sales_channel, store_id | text | Where the order was sold and, when it has one, its store (see Store and sales channel). sales_channel is always there. |
A property the store did not send is left out, never sent empty. The event is written after Joryio has decided which cart the order closed, so a journey triggered on Order Completed already sees these values. Each order has exactly one Order Completed, written the first time Joryio receives the order, at the time the order was placed: a later update of the same order (a status change, a cancellation, a refund) never writes another one and never starts the journey a second time.
For example, a journey triggered on Order Completed with the condition recoveredCart is true can thank a shopper who came back for their cart.
Refunds
Refund status and the refunded amount sync from Shopify and WooCommerce (and can be sent by a custom integration via totalRefunded on the Orders API). Every revenue figure on the page - and in attribution - is net of refunds: a partial refund reduces the order's net revenue, and a fully-refunded order contributes nothing to its campaign's credit.
Refund and cancellation events
Every connected store and the Orders API turn a new refund or a cancellation into an event you can start a journey or build a segment on:
| Event | When | Key properties |
|---|---|---|
Order Refunded | Once per refund, full or partial | order_id, total (the amount this refund returned, in the order currency), total_base (in your base currency), currency, refund_type (full or partial), refund_amount (same as total), refund_id, reason, products (refunded line items, when the store lists them), coupon_codes, sales_channel, store_id |
Order Cancelled | Once per order | order_id, total, currency, reason, cancelled_at, coupon_codes, sales_channel, store_id |
Once, whichever way it arrives. A store reports the same refund more than once - a webhook redelivery, the plugin and a webhook both, a re-run sync. Joryio compares each order update with the order as it was stored: only a refund that is not counted yet produces an event, and an update older than the stored order is ignored. Each event has a fixed ID (the store's refund ID when it gives one), so a journey enters once per refund.
| Source | Refund | Cancellation |
|---|---|---|
| Shopify | Each refund, with its own ID, date, note and refunded items | cancelled_at, with Shopify's cancel reason |
| WooCommerce | Each refund ID on the order (dated by the order's last update); the plugin's refunded status counts as a full refund | Status cancelled (also a failed payment, or an order deleted in WooCommerce) |
| Magento | Each rise of the order's refunded total, picked up by the order sync; status closed (sent live by the extension) counts as a full refund | Status canceled |
| Orders API | refunds on the order (one event per id), totalRefunded, status refunded, or POST /orders/:id/refund | Status cancelled, or POST /orders/:id/cancel |
Past orders. The first sync of a store records refunds and cancellations of past orders in your event history at their own date (when it is within the last two years; older ones are skipped), the same way it records their Order Completed. Like those, they never start a journey: only changes that arrive live do.
Revenue is not reduced twice. Revenue reports, attribution and RFM already net refunds from the order itself, and leave cancelled and fully refunded orders out. Order Refunded and Order Cancelled are not revenue: no report subtracts them.
If you also send orders from an SDK, do not call the trackers' orderRefunded / orderCancelled for orders a store or the Orders API already sends - each refund would be recorded twice.