How to Build a Daily Multi-Source Revenue Roll-Up Across Shopify, Stripe and NetSuite
Build a scheduled Spojit workflow that fans out to Shopify, Stripe and NetSuite at the same time, sums each channel's revenue, and emails one consolidated figure with a per-channel breakdown every morning.
What This Integration Does
Most teams pull yesterday's numbers from three places by hand: Shopify orders, Stripe charges, and NetSuite sales orders. This Spojit workflow does that roll-up for you on a fixed schedule. It reads each channel, totals the revenue per channel using the math connector, adds the three totals into a single consolidated figure, and sends a plain-text email so the first thing in your inbox each morning is yesterday's revenue with the source-by-source split.
The workflow is started by a Schedule trigger on a cron expression (for example 0 7 * * * in your reporting timezone), so it runs unattended every day with no input. A Parallel node fans out into three concurrent branches that query Shopify, Stripe and NetSuite at once, which keeps the run fast instead of querying them one after another. Each branch produces a channel total, a final Transform step assembles the breakdown, and a Send Email node delivers it. The workflow holds no state between runs: each run reports a fresh window, so re-running it for the same day simply produces the same report again (and sends another email).
Prerequisites
- A Shopify connection (API key) added under Connections, with read access to orders.
- A Stripe connection (API key) with read access to charges.
- A NetSuite connection with read access to sales orders.
- The math connector is built in and needs no connection.
- Your reporting recipient on the org email allowlist (Settings -> General -> Email recipients) so the Send Email node can deliver to it.
- Agreement on what "revenue" means per channel (for example Shopify order
total_price, Stripe chargeamount, NetSuite sales order total) and which currency you report in.
Step 1: Start the workflow on a Schedule trigger
On a new workflow canvas, set the Trigger node type to Schedule. Add a 5-field Unix cron expression and an IANA timezone so the run fires once a day after the previous day has closed. For a 7am daily roll-up in Sydney, use:
Cron: 0 7 * * *
Timezone: Australia/Sydney
The trigger output is { scheduledAt }. Use the date portion of {{ trigger.scheduledAt }} later if you want to compute the previous day's window. A single Schedule trigger can hold multiple schedules, so you can add a second cron line if you also want a midday refresh.
Step 2: Fan out to all three systems with a Parallel node
Add a Parallel node straight after the trigger and give it three branches: one for Shopify, one for Stripe, one for NetSuite. All three branches run concurrently, so the total wait is roughly the slowest single channel rather than the sum of all three. Each branch will contain a Connector node in Direct mode to pull records, followed by a math sum to total that channel. Name your branch output variables clearly (for example shopify_total, stripe_total, netsuite_total) so the final Transform step can reference them.
Step 3: Pull and total Shopify orders
In the Shopify branch, add a Connector node in Direct mode on the shopify connector and pick the list-orders tool. Scope it to the previous day and to paid orders so the figure matches your accounting view. A typical input:
{
"status": "any",
"financial_status": "paid",
"created_at_min": "2026-06-20T00:00:00+10:00",
"created_at_max": "2026-06-20T23:59:59+10:00",
"limit": 250
}
Store the result as shopify_orders. Add a Transform node to pull the per-order totals into a flat array of numbers, for example mapping each order to its total_price and producing shopify_amounts. Then add a Connector node in Direct mode on the math connector with the sum tool, mapping its numbers input to {{ shopify_amounts }}. Save the math output as shopify_total; the sum is returned as {{ shopify_total.result }}.
Step 4: Pull and total Stripe charges
In the Stripe branch, add a Connector node in Direct mode on the stripe connector and pick the list-charges tool, scoped to the same day. Filter to successful, captured charges so refunds and failed attempts do not inflate the figure:
{
"created": { "gte": 1718805600, "lte": 1718891999 },
"limit": 100
}
Save the result as stripe_charges. Stripe amounts are in the smallest currency unit (for example cents), so in a Transform node build an array of the captured charge amounts and divide each by 100 to get a dollar value, producing stripe_amounts. Then add a math sum Connector node mapping numbers to {{ stripe_amounts }} and save the output as stripe_total, available as {{ stripe_total.result }}. If you expect more than 100 charges per day, see the Common Pitfalls note on pagination.
Step 5: Pull and total NetSuite sales orders
In the NetSuite branch, add a Connector node in Direct mode on the netsuite connector. The cleanest way to scope sales orders by date is the run-suiteql tool, which lets you sum directly in the query and return one row:
SELECT SUM(foreigntotal) AS revenue
FROM transaction
WHERE type = 'SalesOrd'
AND trandate = TO_DATE('2026-06-20', 'YYYY-MM-DD')
Save the result as netsuite_result. If you prefer to list and total in Spojit instead, use the list-sales-orders tool, then a Transform node to build a number array and a math sum node as in the other branches. Either way, expose the channel figure as netsuite_total (for example {{ netsuite_result.rows[0].revenue }} from SuiteQL, or {{ netsuite_total.result }} from a math sum).
Step 6: Combine the three channels and assemble the report
After the Parallel node closes, add a Connector node in Direct mode on the math connector with the sum tool to add the three channel totals into the consolidated figure. Map numbers to the three branch results:
{
"numbers": [
{{ shopify_total.result }},
{{ stripe_total.result }},
{{ netsuite_total.result }}
]
}
Save this as grand_total; the consolidated revenue is {{ grand_total.result }}. Optionally run a second math node with the currency tool to format each figure for display. Then add a Transform node that builds the email body text from the channel totals and the grand total, producing a single report_body string.
Step 7: Email the consolidated revenue figure
Add a Send Email node as the final step. It sends from Spojit's built-in mail service, so no connection is required. Fill in Recipients with your finance distribution list (comma-separated, all on the email allowlist), a templated Subject, and the assembled Body:
Subject: Daily revenue roll-up - {{ trigger.scheduledAt }}
Body:
Consolidated revenue: {{ grand_total.result }}
By channel:
Shopify: {{ shopify_total.result }}
Stripe: {{ stripe_total.result }}
NetSuite: {{ netsuite_total.result }}
Set If sending fails to Fail the workflow so a delivery problem shows up as a failed run rather than passing silently. To send from your own domain instead of the built-in service, swap this node for a Connector node on the resend or smtp connector using the send-email tool. If you would rather skip building each branch by hand, ask Miraxa, the intelligent layer across your automation, to scaffold it: "Add a Parallel node with three branches that call Shopify list-orders, Stripe list-charges and NetSuite run-suiteql, then sum each with the math connector and email the total." Miraxa adds and connects the nodes on the canvas, and you fine-tune the fields in the properties panel.
Tips
- Keep all three branches on the same date window. Drive every channel's date filter from
{{ trigger.scheduledAt }}so a late-running schedule never mixes two different days. - Report in one currency. If a channel transacts in multiple currencies, filter or convert in its Transform step before the math
sum, rather than adding mismatched amounts. - Use the math
currencyorroundtool on the final figures so the email shows clean amounts instead of long floating-point values. - Because branches run concurrently in the Parallel node, a slow NetSuite query no longer blocks the Shopify and Stripe pulls; the run finishes near the speed of the slowest single channel.
Common Pitfalls
- Pagination undercounts.
list-ordersandlist-chargesreturn a capped page. On high-volume days you must page through all results (or narrow the window) before summing, otherwise the channel total is silently low. - Timezone drift. A cron in one timezone and date filters in another will straddle midnight and double-count or miss orders. Match the Schedule timezone to the date boundaries you pass each connector.
- Smallest-currency units. Stripe charge amounts are in cents. Divide by 100 in the Stripe Transform step before summing, or your Stripe total will be 100x too high.
- Refunds and unpaid orders. Filter Shopify to paid orders and Stripe to captured, succeeded charges. Counting authorizations, failed attempts or refunded transactions skews the roll-up.
Testing
Before scheduling it daily, validate on a small, known window. Temporarily point each connector's date filter at a single past day whose revenue you already know from each system's own dashboard, then use the Run button to execute the workflow once. Open the run in execution history and check each branch: confirm the Shopify, Stripe and NetSuite record counts look right, that {{ shopify_total.result }}, {{ stripe_total.result }} and {{ netsuite_total.result }} match the source dashboards, and that {{ grand_total.result }} equals their sum. Once the emailed figure matches your manual numbers, enable the Schedule trigger.