Updated
View as MarkdownSales mix
Open Revenue, then choose the Sales mix tab above the headline. The tab shows when a Shopify store is connected. The selected date range carries across; website-visit filters stay on Attribution. This report counts paid orders and refunds directly, including sales with no website visit. It shows net sales, paid orders, average order value and refunds, each against the period before, and net sales over time.
Below the chart: net sales by customer type and by order source, a grid of customer type × order source, net sales per week (or day, or month) stacked by customer type, one card per customer type, and the recent paid orders. All of them reconcile to the filtered totals. Select a row, a grid cell or a card name to filter the page to it.
Customer type and order source
- Customer type: Wholesale, Distributor, D2C or Unknown. You configure which Shopify customer tags mean each type.
- Order source: Online checkout, Draft order, Other or Unknown, from Shopify's order source.
These are independent. A wholesale customer can use the online checkout. A draft order alone does not prove that the customer is wholesale.
Set up customer types
While customer types are off, Sales mix shows a setup card with 3 steps. Owners and members can use it; viewers see a short note.
- Allow access. Choose Allow in Shopify, approve in Shopify and come back. Twelvebit sees the approval by itself; Check again is there if it does not. The public app requests the optional
read_customersscope. A legacy custom app needs the same scope on its own installation. - Match tags. Twelvebit lists the customer tags in your store with the number of customers for each. Choose Wholesale, Distributor, D2C or Not used for each tag. Tags with a clear name are pre-selected. You can add a tag that is not in the list. Then choose what happens to customers with no matching tag (D2C or Unknown) and choose Save and continue. Saving turns customer types on.
- Import past orders. Choose Last 60 days, All past orders (when Shopify allows older orders) or Skip for now.
To change the matches later, choose Customer types at the bottom of Sales mix. Turn customer types off is in the same step. Customer types are optional. Turning them on or off does not change live Revenue dates, website attribution, visitor reporting or how sales amounts are recorded. Existing customer labels remain as recorded. Granting permission alone does not enable classification. D2C means direct to consumer.
Tag matches ignore case. Different tags that imply conflicting types leave the customer Unknown. The same tag cannot be mapped to two types. Customers with no mapped tag stay Unknown unless you explicitly choose D2C for that case. Failed lookups always stay Unknown. Names are not read or matched. The sales report stores the normalized type rather than copying the customer's raw tag list. Webhook deliveries use the existing temporary retry queue.
Live sales keep their customer-type snapshot at payment. Later tag or mapping changes apply to future sales and do not rewrite classified orders. Refunds inherit the original sale's type and source, including when a refund arrives before customer enrichment completes. A Shopify lookup failure keeps the money and allows enrichment to retry.
Paid draft orders
A draft is counted after Shopify sends orders/paid. Open drafts, quotes and completed orders awaiting payment are not sales in this report. The source shopify_draft_order is Draft order; web is Online checkout; another known source is Other.
Live orders keep the existing Revenue attribution rules, including browser and previous-customer matching where available. Historical imports only attach to an explicit tracking or checkout link; they do not infer website conversions from a previous purchase. Orders with no linked visit still count in Sales mix. Full visitor and funnel segmentation is a separate capability.
Import available history
Choose Import past orders at the bottom of Sales mix (or step 3 of the setup). It is available with customer types off. Choose Last 60 days or All past orders, then Start import. Shopify normally permits the last 60 days. Older history requires Shopify approval for read_all_orders and a merchant grant. The app offers a link to grant it when the scope is available for the app.
The import reads paid orders, their completed refunds and their order sources. It skips test orders and unpaid orders. The date selects orders created since that date; revenue is dated from the latest successful sale/capture transaction when available. Current customer tags classify previously unresolved history, with an Imported · today’s tags label in the recent orders. This is not a reconstruction of past tag values. Already classified sales keep their snapshots, including classifications saved as Unknown. The import result shows its creation-date window and processed-order count; a completed import does not imply that all lifetime orders are available.
Imports page through Shopify under a lease, save a cursor and resume while the page is open or through the sync cron after it closes. Retrying does not duplicate money. Imports send no payment alerts and create no historical conversion goals. An error keeps recorded sales; check the access in Shopify, then choose Try again. Missing permission or unavailable history is never treated as zero historical sales.
Understand Unknown customer types
Open How customer types work under the customer-type breakdown. Orders that have not yet been classified may be eligible for classification by importing available Shopify history after setup. Orders already checked and saved as Unknown keep that snapshot: they may have had no matching tag, conflicting tags or no available customer. New tag mappings apply to future paid orders. History import cannot reconstruct past tags or rewrite a saved classification.
Filter and save a view
Choose a Customer type chip and an Order source chip. The filters live in the URL, so you can share the view. To reuse them, choose Save view beside the date range, enter a name and choose Save. Saved views are in the menu beside the date range. They remember the two sales filters while keeping your selected date range. Owners and members can save or delete views; viewers can apply them. These are stored as sales segments in the API, separate from website-visit segments.
In the API and MCP, customers (known paying customers) counts distinct provider/shop customer ids, emails or visitor ids. Orders with no customer identity still count toward sales and orders but cannot establish a distinct customer count.
API and MCP
curl 'https://twelvebit.app/api/v1/sales?period=30d&customer_type=wholesale&order_source=draft_order' \
-H 'Authorization: Bearer YOUR_KEY'The endpoint returns totals, previous-period totals, customer-type and order-source breakdowns, the trend, recent payments and classification coverage. It accepts period, from, to, g, customer_type and order_source, plus site for account keys. Amounts use the site's currency. Website visit filters are not accepted.
GET /api/v1/sales/segments lists sales segments. POST saves { "name": "Wholesale drafts", "filters": { "customer_type": "wholesale", "order_source": "draft_order" } }. DELETE ?id=… deletes a segment. Writes need write:config and an owner or member role; reads need read.
The MCP tool is get_paid_sales, with site, period or from/to, and optional customer_type and order_source. It uses the same report as the dashboard and REST API.