How to Email a Daily Stripe Revenue Summary to Finance
Build a scheduled Spojit workflow that pulls the day's Stripe charges, totals them with the math connector, and emails a clean revenue summary to your finance team every morning.
What This Integration Does
Finance teams usually start the day asking the same question: how much did we take in yesterday? Instead of logging into Stripe and exporting a CSV by hand, this workflow does it for you. On a fixed schedule it lists the charges Stripe recorded during the previous day, keeps only the successful ones, adds up the amounts per currency, and sends a formatted summary email. The result is a predictable, audit-friendly daily figure that lands in the finance inbox before anyone has opened their laptop.
The workflow runs on a Schedule trigger, so nothing external has to call it. Each run computes a 24-hour window in your reporting timezone, pages through Stripe's list-charges results, filters by each charge's created timestamp and status, sums the captured amounts with the math connector, and finishes with a Send Email step. It is read-only against Stripe and writes nothing back, so re-running it (for example to re-send yesterday's figure) is completely safe and produces the same totals as long as the underlying charges have not changed.
Prerequisites
- A Stripe connection added under Connections -> Add connection, using an API key with read access to charges. See the Stripe connector article for setup details.
- The finance recipient addresses. If any are outside your organization, add them to the allowlist under Settings -> General -> Email recipients (see Configuring the Email Allowlist).
- Agreement on your reporting timezone (for example
Australia/SydneyorAmerica/New_York) so the daily window matches what finance expects. - The currency or currencies your account settles in. Stripe amounts are returned in the smallest unit (cents for USD), so you will divide by 100 for display.
Step 1: Add the Schedule trigger
Create a new workflow in the Workflow Designer and set the Trigger node type to Schedule. Add a 5-field cron expression and an IANA timezone. To run at 7:00 every weekday morning in Sydney, use:
Cron: 0 7 * * 1-5
Timezone: Australia/Sydney
The trigger output is { scheduledAt }, the moment the run fired. You will use this as the anchor for "yesterday". A single Schedule trigger can hold multiple schedules if you later want a second send time, but one entry is enough here.
Step 2: Compute yesterday's date window
Add a Connector node in Direct mode using the date connector. You need the start and end of the previous day as Unix timestamps so you can compare them against each charge's created value. First call start-of on {{ trigger.scheduledAt }} with unit day in your timezone to get the start of today, then call subtract to step back one day, and unix to convert both boundaries.
A simpler approach is to use the code connector's execute-javascript tool to derive both boundaries in one step and return them as numbers:
{
"windowStart": 1718668800,
"windowEnd": 1718755200,
"label": "17 June 2025"
}
Save the output to a variable such as window. windowStart is inclusive midnight at the start of yesterday and windowEnd is midnight at the start of today, both in seconds to match Stripe's created field.
Step 3: List the day's Stripe charges
Add a Connector node in Direct mode, choose your Stripe connection, and select the list-charges tool. Stripe returns charges newest-first, so set limit to 100 (the maximum) to pull a full page. The tool also accepts starting_after, a charge ID cursor used for pagination.
Because the connector lists charges in descending creation order, you can keep requesting pages until a returned charge's created falls before {{ window.windowStart }}, at which point you have passed your window. For low volume accounts a single page of 100 is often enough for one day; for higher volume, wrap this step in a Loop node (While) that advances starting_after with the last charge ID until you cross the window boundary. Collect the matching charges into a variable named charges.
Step 4: Filter to yesterday's successful charges
Add a Transform node to reshape the raw list into just the rows that count toward revenue. Keep a charge only when all three conditions hold: its created is greater than or equal to {{ window.windowStart }}, its created is less than {{ window.windowEnd }}, and its status equals succeeded (you can also require paid to be true). Group the survivors by currency so multi-currency accounts total correctly.
Produce a tidy structure the next steps can consume, for example:
{
"usd": [4200, 1599, 9900],
"aud": [25000],
"count": 4
}
Each array holds amount values in the smallest currency unit. Save this to a variable such as filtered.
Step 5: Total the amounts with the math connector
Add a Connector node in Direct mode using the math connector and its sum tool. Pass the array of amounts for a currency, for example {{ filtered.usd }}, to get the gross total in cents. Then use the math currency tool (or a calculate / round call dividing by 100) to format the cents into a readable amount. If you settle in more than one currency, run a sum per currency, either as separate nodes or inside a Loop over each currency key.
For an at-a-glance average ticket size you can also call the math average tool on the same array. Store each total in its own variable, for example totalUsd and countUsd, so the email body can reference them directly.
Step 6: Email the summary to finance
Add a Send Email node, which uses Spojit's built-in mail service and needs no extra connection. Set Recipients to your finance list (comma-separated), templated where useful, and a clear Subject. Compose a plain-text Body that pulls in the variables you built:
Subject: Stripe revenue for {{ window.label }}
Hi Finance team,
Here is yesterday's Stripe summary for {{ window.label }}.
Successful charges: {{ filtered.count }}
Gross (USD): {{ totalUsd }}
Average charge (USD): {{ avgUsd }}
This summary was generated automatically by Spojit.
Set Reply-To if you want replies to reach a shared mailbox rather than the workflow owner, and set If sending fails to Fail the workflow so a delivery problem surfaces in your execution history instead of passing silently.
Tips
- Stripe stores
createdin UTC. Always derive your window boundaries in your reporting timezone and convert to Unix seconds before comparing, or your "day" will drift by your UTC offset. - Keep
limitat100and paginate withstarting_afterrather than guessing a smaller page size, so busy days are never truncated. - If you want the figure formatted with a currency symbol and thousands separators, the math
currencytool handles that, so you do not have to template number formatting by hand. - To add a Slack heads-up alongside the email, fan out with a Parallel node and add a Slack connector
send-messagebranch. See the subscription alerts tutorial for the pattern.
Common Pitfalls
- Counting refunds or failed attempts. Filter on
statusequal tosucceeded; if you need net revenue, subtractamount_refundedfromamountper charge before summing. - Mixing currencies into one total. A USD charge of
4200and an AUD charge of4200are not8400of anything. Group bycurrencyfirst. - Forgetting the smallest-unit convention. Stripe returns
amountin cents, so divide by 100 only at display time and keep the raw integers for the mathsum. - An empty day. If there were zero charges, your arrays will be empty. Add a Condition node so the email clearly says "No charges recorded" instead of sending a blank total.
Testing
Before scheduling, test on a small scope. Temporarily switch the trigger to Manual and use the Run button so you can inspect each step's output in the execution log. Hard-code windowStart and windowEnd to a recent day you can verify against the Stripe dashboard, confirm list-charges returns the rows you expect, and check that the math sum total matches the dashboard figure exactly. Point the Send Email recipients at your own address first. Once the numbers reconcile, switch the trigger back to Schedule and add the finance recipients. You can also ask Miraxa, the intelligent layer across your automation, "Why did my last run total nothing?" to investigate an empty or unexpected result.