How to Send Renewal Reminder Emails to Stripe Subscribers Before They Lapse

Run a daily Spojit workflow that lists active Stripe subscriptions due to renew soon, looks up each subscriber's details, and sends a branded reminder email through Resend before the renewal date arrives.

What This Integration Does

Subscription churn is often quiet: a card silently expires, a customer forgets the renewal is coming, and the first time anyone notices is when the payment fails. A proactive reminder a few days before renewal gives customers time to update their card or cancel cleanly, which reduces failed payments and support tickets. This workflow watches your Stripe subscriptions on a schedule, finds the ones renewing within a window you choose, and emails each subscriber a friendly heads-up from your own domain using the Resend connector.

The workflow is driven by a Schedule trigger, so nothing has to call it: Spojit wakes it up on a cron expression (for example once every morning) and the run reads the current state of Stripe each time. It pulls active subscriptions, computes how many days remain until each current_period_end, keeps only the ones inside your reminder window, resolves the customer email for each, and sends one Resend email per match. The workflow does not write anything back to Stripe; it is read-and-notify only, so a re-run is safe. Because Stripe is queried fresh every run, subscriptions that already renewed or cancelled simply fall out of the results on the next pass.

Prerequisites

  • A Stripe connection in Spojit (API key) with read access to subscriptions and customers. See the Stripe connector docs.
  • A Resend connection in Spojit (API key) with a verified sending domain, so reminders come from your own address. See the Resend connector docs.
  • A decision on your reminder window (for example "renews within the next 3 days") and the timezone the schedule should run in.
  • A short reminder email template: subject line and body copy you are happy to send to customers.

Step 1: Add a Schedule trigger

Start a new workflow and set the Trigger node type to Schedule. A Schedule trigger uses a 5-field Unix cron expression plus an IANA timezone. To run every morning at 9am in Sydney, use the cron 0 9 * * * with timezone Australia/Sydney. The trigger output is { scheduledAt }, which you can reference later as {{ trigger.scheduledAt }}. One trigger can hold several schedules if you want more than one run per day.

Step 2: List subscriptions due to renew

Add a Connector node in Direct mode, choose the Stripe connection, and select the list-subscriptions tool. Set status to active so you only consider live subscriptions, and set limit to a reasonable page size such as 100 (the maximum). Each returned subscription includes customer (the Stripe customer ID), status, cancel_at_period_end, and current_period_end (a Unix timestamp, in seconds, of the next renewal). Save the result to a variable like subs.

{
  "status": "active",
  "limit": 100
}

If you have more than 100 active subscriptions, capture the last subscription ID from the page and pass it as starting_after in a follow-up call to page through the rest. For most catalogs a single page per run is enough.

Step 3: Keep only subscriptions inside your reminder window

Add a Transform node to reshape the subscription list down to the ones renewing soon. Compute, for each subscription, the number of days between now and current_period_end, and keep only those that fall inside your window (for example 0 to 3 days away) and where cancel_at_period_end is not already true (no point reminding someone who has chosen to cancel). The output should be a clean list of subscriptions to remind, each carrying its customer ID and a human-readable renewal date.

If you prefer to express the date math explicitly, use a Connector node with the Date & Time utility connector and its diff tool to compare current_period_end against now, then filter with the Array connector's filter tool. Either approach leaves you with a short list, for example saved as dueSoon.

Step 4: Loop over each due subscription

Add a Loop node in ForEach mode and point it at {{ dueSoon }}. Everything inside the loop body runs once per subscription, with the current item available as the loop's item variable (for example {{ subscription }}). This is where you look up the customer and send their reminder, so each subscriber gets exactly one tailored email per run.

Step 5: Look up the customer's email and name

Inside the loop, add a Connector node in Direct mode using the Stripe connection and the get-customer tool. Pass the subscription's customer ID into the customer_id field as {{ subscription.customer }}. The response includes the customer's email and name, which you will use to address and personalize the message. Save it as customer.

{
  "customer_id": "{{ subscription.customer }}"
}

Some customer records have no name or no email on file. Add a Condition node that checks {{ customer.email }} is present before sending, so a missing address skips that subscriber instead of failing the run.

Step 6: Send the branded reminder with Resend

Still inside the loop, add a Connector node in Direct mode using the Resend connection and the send-email tool. Set from to an address on your verified domain (for example billing@yourbrand.com), to to {{ customer.email }}, a clear subject, and an html body that pulls in the customer's name and renewal date. Because Resend sends from your own verified domain, the email carries your branding rather than a generic system address.

{
  "from": "Your Brand ",
  "to": "{{ customer.email }}",
  "subject": "Your subscription renews soon",
  "html": "<p>Hi {{ customer.name }},</p><p>Your subscription is set to renew on {{ subscription.renewalDate }}. If your card or details have changed, please update them before then so your service continues without interruption.</p><p>Thanks,<br>The Your Brand Team</p>"
}

If you would rather send a one-line plain message from Spojit's built-in mail service instead of your own domain, you can swap this for a Send Email node, but the Resend connector is the right choice when you need the reminder to come from your brand address. Not sure when to use each? Compare with the guide to building email notifications with Resend.

Tips

  • Keep the cron simple and run once a day. A subscriber should get a single reminder, not one per hour. If you want a second nudge, add a separate window (for example also remind at exactly 1 day out) and dedupe carefully.
  • Stripe's current_period_end is a Unix timestamp in seconds. Convert it to a readable date with the Date & Time connector's format tool before placing it in the email so customers see a real date, not a number.
  • Use Miraxa, the intelligent layer across your automation, to scaffold the skeleton fast. Try a prompt like "Add a Loop node over {{ dueSoon }}, then inside it a Stripe get-customer Connector node and a Resend send-email Connector node, and connect them," then fine-tune fields in the properties panel.
  • Set the Resend node's failure behavior so one bad address does not abort the whole batch: let the loop continue past a single send failure rather than halting every remaining reminder.

Common Pitfalls

  • Timezone drift. Cron runs in the IANA timezone you pick. If your reminder window is "3 days out" but the schedule runs in UTC while your customers think in local time, reminders can land a day early or late. Match the schedule timezone to how you describe the window.
  • Reminding cancellations. A subscription with cancel_at_period_end set to true is winding down on purpose. Filter these out in Step 3 so you do not nudge someone who already chose to leave.
  • Unverified Resend domain. If your sending domain is not verified in Resend, send-email will be rejected. Verify the domain first; you can confirm status with the Resend get-domain or list-domains tool.
  • Pagination. list-subscriptions returns at most 100 per call. If you have more active subscriptions than that and only read the first page, later subscribers never get reminded. Page with starting_after or narrow the window so each run stays under the page size.

Testing

Before turning the schedule loose, test on a tiny scope. Temporarily filter Step 2 to a single test customer by adding a Condition that only proceeds for one known customer ID, or point the Resend to field at your own inbox so the loop sends every reminder to you instead of real subscribers. Run the workflow with the Run button (you can trigger a Schedule workflow manually for testing) and check the execution log: confirm the subscription list looks right, the day-count filter kept the correct rows, get-customer resolved a real email, and the Resend send succeeded. Once the sample email arrives looking the way you want, restore the real to field and enable the schedule.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.