Skip to main content
Subscription businesses lose customers to involuntary churn: expired cards, forgotten renewals, surprise charges that trigger refund requests. A tiered reminder sequence gives customers time to update their payment details, change their plan, or confirm they want to stay.
Which subscriptions is this for? This recipe is for subscriptions kept in your own site’s database, for example a membership app you built that charges through your own Stripe account. If you bill clients with Hiveku subscriptions, you don’t need it: Hiveku already emails an upcoming charge notice three days before each card renewal and a receipt after each charge, and retries declined cards on its own. To add your own steps to those, see Hiveku subscriptions below.
Before you start, you’ll need a subscriptions (or customers) table in your site’s database with a renewal_date column, and email sending set up. See Send Emails.

The Flow at a Glance

7 days out

Gentle heads-up

3 days out

Upgrade/downgrade options

1 day out

Last chance to change

Day of

Receipt or payment retry

Step 1: Create the Workflow

1

Open Workflows

Go to Workflows and click New Workflow. Name it Subscription Renewal Reminders.
2

Add a Scheduled Trigger

Add a Scheduled Trigger. Set Frequency to Daily, set the Hour and Minute (for example 8:00), and pick your Timezone. The schedule runs in UTC unless you change it.
Pick a time when customers are likely to open email but before support staff clock in. It gives them a chance to handle issues themselves first.

Step 2: Query Upcoming Renewals

Add a Run SQL Query step pointed at your site’s database. Each tier uses its own query so you can send different messages. Here’s the 7-day query as a template:
Add three more queries with adjusted date ranges and sent-flag columns for the 3-day, 1-day and day-of tiers.
Always check a renewal_reminder_*_sent flag in the query. Without it, a single customer can get the same reminder several times if the workflow runs more than once a day or is switched back on mid-window.

Step 3: Send Tiered Reminder Emails

Different days, different tone:
  • 7 days out: “Your plan renews next week”. Casual and reassuring. Include the plan name and renewal amount, with one soft call to action: “Manage your subscription.”
  • 3 days out: “Renewing in 3 days”. Introduce upgrade and downgrade options, and highlight what a higher tier adds.
  • 1 day out: “Your subscription renews tomorrow”. The last chance to change anything. Put the link to update payment details up front.
  • Day of: either a “Thanks for renewing” receipt, or a “Renewal failed: update your payment details” notice, depending on the charge result.
1

Loop over the rows

After each query, add a For Each (Loop) step. In List to loop over, reference the query’s rows (typing {{ lists what earlier steps produced). The steps on its Each item exit run once per row and read the row as {{ forEach.item }}.
2

Send the email

On Each item, add a Send Email step. Set To to the row’s email column, for example {{ forEach.item.user_email }}, and write the Subject and body for that tier.
3

Personalize per plan

Monthly customers get different messaging than annual ones, and high-tier customers deserve a more personal touch. Branch with a Condition (If) step, or split the tiers into separate workflows.
4

Mark the reminder as sent

After the email, still inside the loop, add a Run SQL Query step that sets the flag. Pass the row’s id in Params (JSON array) instead of typing {{...}} into the SQL:
Params (JSON array): ["{{ forEach.item.id }}"]

Step 4: Handle Failed Renewals

A failed payment is often an expired or replaced card rather than a decision to leave, so it’s worth a follow-up. If your site charges through your own Stripe account, build a second workflow for this:
1

Create a new workflow

Name it Renewal Recovery.
2

Add an Inbound Webhook trigger

Add an Inbound Webhook trigger and copy its URL. Point a Stripe webhook for the invoice.payment_failed event at that URL. See Webhook Patterns for protecting it. The event’s data arrives under trigger.output.payload.
3

Send a recovery email

Add a Send Email step. Subject: “Your payment didn’t go through.” Body: plain and calm. Explain what happened, link to where they update their payment details, and say what happens if they don’t.
4

Follow up

Add a Wait Until step (for example 2 days), then another Send Email with a little more urgency, and repeat once or twice. Use Wait Until rather than Delay, which is for waits under 15 minutes. Before each follow-up, check your own database with a Run SQL Query and a Condition (If) step, so a customer who has already paid isn’t chased. What happens to an account that never pays is up to your app.
Renewal emails tend to get read. Use the attention to share what’s new since the last billing cycle, highlight features the customer hasn’t tried, or tease an upcoming release.

Loyalty Incentives

Tenure is a retention lever. Use it in your renewal emails:
  • “You’ve been with us 1 year: here’s 10% off next month”
  • “Celebrating 6 months: unlocked priority support”
  • “Year 2 with Acme: we upgraded you to the new Pro features at no extra cost”
Calculate tenure from created_at in your subscription record and branch the email on thresholds.

Personalize by Plan

One-size-fits-all reminders get unsubscribes. Branch your messaging:
  • Monthly vs annual: annual customers need less hand-holding but bigger-deal framing (“your annual plan renews in 30 days”)
  • Free trial converting to paid: emphasize what they’ll lose if they cancel vs what they’ve already set up
  • High-tier: consider a personal email from a human, not a templated one
  • At-risk (low usage): combine the renewal reminder with a “need help getting started?” offer

Hiveku subscriptions

If you bill clients with Hiveku subscriptions, Hiveku sends these on its own:
  • An Upcoming charge email three days before each card renewal.
  • A receipt after each charge, or the invoice by email when there’s no card.
  • Automatic retries of a declined card: 3 days later, then 7 days after that.
See What the client receives and Failed payments. To run your own steps on top, start a workflow with a Subscription Trigger. It fires on:
  • subscription.created: a client was subscribed.
  • subscription.renewed: a new period was billed, either charged to the card or emailed as an invoice.
  • subscription.past_due: a renewal charge was declined.
  • subscription.cancelled: the subscription ended.
List the events you want in its Event types field, separated by commas, or leave it blank for all of them.
The Run SQL Query steps in this recipe read your site’s own database, not Hiveku subscriptions, and there’s no trigger for “renews in N days”. No workflow step pauses or cancels a Hiveku subscription: do that from the subscription’s page.

Verify It Worked

1

Create a test subscription

Insert a test row with renewal_date = now() + interval '7 days'.
2

Trigger the workflow

Wait for the next scheduled run, or ask an AI agent connected to your account to run the workflow once for real. The editor’s Test Run is a dry run: sending and saving steps are simulated, and read steps use your live data.
3

Confirm the email arrives

Check the test inbox. Verify the subject, tone and links render correctly, and confirm the renewal_reminder_7d_sent flag was set.
4

Reset and test other tiers

Update the test row to now() + interval '3 days', clear the flag, and run again.

Troubleshooting

Check that the workflow shows Enabled in the editor. Then check the renewal_reminder_*_sent flag on the target row: if it’s already set, the query filters the row out. To re-test, clear the flag and run again.
Date math is tricky. Make sure your BETWEEN ranges don’t overlap: the 7-day window should end exactly where the 3-day window begins. Also check that your database’s timezone matches the Timezone on the Scheduled Trigger.
The 7-day email is the one most often missed: spam folder, busy week, address change. Send a day-of confirmation too, even for successful renewals, so they have at least one message they can search their inbox for.
If the email workflow runs but Stripe payments aren’t going through, the issue is at the payment layer, not the email layer. Keep email sending and payment retries independent, so each succeeds or fails on its own. Check your Stripe API logs and webhook configuration.
Usually a sent-flag race. Make sure the flag update happens before the next workflow run, or use a uniqueness constraint like UNIQUE(subscription_id, reminder_tier, date) on a reminders log table.

What’s Next?

Add Stripe

Wire up subscriptions and payment processing on your site

Webhook Patterns

Handle Stripe and other third-party webhooks reliably

Hiveku Subscriptions

Plans, renewals and the emails Hiveku sends for you