How to Notify Slack When a Stripe Subscription Upgrades or Cancels
Build a Spojit workflow that receives Stripe subscription change events, classifies them as an upgrade, downgrade, or churn, posts a deal-change alert to your revenue Slack channel, and keeps the matching Monday.com CRM card in the right stage.
What This Integration Does
When a customer changes their plan, your revenue team usually finds out late: someone notices the MRR number moved at month end, or a churned account sits in the wrong CRM column for weeks. This workflow closes that gap. The moment Stripe records a customer.subscription.updated or customer.subscription.deleted event, Spojit reads the change, works out whether it is an upgrade, a downgrade, or a cancellation, and tells the people who care: it posts a formatted message to Slack and moves the account's card on a Monday.com board to the correct group so your pipeline always reflects reality.
A Webhook trigger starts the run when Stripe sends an event to the workflow's URL. The webhook body carries the subscription object plus a previous_attributes diff that tells you exactly what changed. A Connector node on the stripe connector resolves the human-readable plan and price, a Transform node computes the MRR delta and a change type, a Condition node routes on that type, and the final steps fan the result out to Slack and Monday.com. Each Stripe event triggers one independent run; there is no shared state between runs, so re-sending the same event simply produces the same alert and the same idempotent card move.
Prerequisites
- A stripe connection (API key) added under Connections, with permission to read customers and subscriptions.
- A slack connection authorized to post to your revenue channel (for example
#revenue-alerts), and the channel ID or name handy. - A monday connection, plus the board ID where your accounts live and the column/group IDs for stages such as
Active,Expansion, andChurned. - A signing connection for the webhook. Stripe signs its webhooks, so create a webhook connection using the Custom scheme with your Stripe signing secret, or use the Spojit scheme during testing. See Setting Up a Webhook Connection.
- A mapping from Stripe price IDs to a numeric monthly amount, so the workflow can compare old and new plans. Keep this small lookup in the workflow as a Transform table.
Step 1: Receive the Stripe event with a Webhook trigger
Add a Trigger node and set its type to Webhook. Spojit gives you a unique URL and returns 202 with an executionId to Stripe on receipt. Attach your signing connection so unsigned or tampered requests are rejected. In Stripe's dashboard, add this URL as a webhook endpoint and subscribe it to two events: customer.subscription.updated and customer.subscription.deleted.
The parsed event body is available as {{ input }}. For both event types the subscription lives at {{ input.data.object }}, and on an update the diff lives at {{ input.data.previous_attributes }}. A typical update body looks like this:
{
"type": "customer.subscription.updated",
"data": {
"object": {
"id": "sub_1Q...",
"customer": "cus_Nv...",
"status": "active",
"items": { "data": [ { "price": { "id": "price_pro", "unit_amount": 9900 } } ] }
},
"previous_attributes": {
"items": { "data": [ { "price": { "id": "price_basic", "unit_amount": 2900 } } ] }
}
}
}
Enable opt-in deduplication using Stripe's event id header so a redelivered event does not fire a second alert.
Step 2: Resolve the plan and customer with the stripe connector
The webhook body is enough for the price diff, but you will want the customer's display name for the alert and a confirmed current subscription state. Add a Connector node on the stripe connector in Direct mode and select the get-customer tool, mapping its input to the customer id from the event:
{ "customer": "{{ input.data.object.customer }}" }
Bind the result to a variable such as customer. If you prefer to re-read the live subscription rather than trust the webhook snapshot (useful when events can arrive out of order), add a second Connector node in Direct mode using the list-subscriptions tool filtered to that customer:
{ "customer": "{{ input.data.object.customer }}", "status": "all", "limit": 1 }
Use Direct mode here because each call is a single deterministic lookup with no AI cost. For multi-step reasoning you would switch to Agent mode, but you do not need it for a plain record fetch.
Step 3: Compute the MRR delta and change type in a Transform node
Add a Transform node to turn the raw price diff into a clean, comparable result. Read the new price from {{ input.data.object.items.data.0.price }} and the previous price (on updates) from {{ input.data.previous_attributes.items.data.0.price }}. Stripe amounts are in the smallest currency unit, so divide unit_amount by 100 for a monthly figure. Produce a single object the rest of the workflow can rely on:
{
"customerName": "{{ customer.data.name }}",
"oldPriceId": "{{ input.data.previous_attributes.items.data.0.price.id }}",
"newPriceId": "{{ input.data.object.items.data.0.price.id }}",
"oldMrr": 29,
"newMrr": 99,
"delta": 70,
"eventType": "{{ input.type }}"
}
Set changeType from these values: if eventType is customer.subscription.deleted, mark it churn; otherwise if delta is greater than zero mark it upgrade, if less than zero mark it downgrade, and if zero mark it no-change so you can drop noise such as quantity-only edits.
Step 4: Route by change type with a Condition node
Add a Condition node that branches on the changeType you just computed. The cleanest pattern is to short-circuit the noise first: on the false branch of a check for {{ transform.changeType }} equal to no-change, end the run. On the true (real change) branch, send everything forward to the notification steps. If you want fully separate copy per outcome, chain two more Condition nodes, testing upgrade then churn, so each path can carry its own Slack wording and its own Monday.com target group. Keep the conditions reading from the Transform output rather than re-deriving the diff, so the routing logic stays in one place.
Step 5: Post a deal-change alert to Slack
Add a Connector node on the slack connector in Direct mode and select the send-message tool. Target your revenue channel and template the body from the Transform output and the customer record:
{
"channel": "#revenue-alerts",
"text": ":chart_with_upwards_trend: *{{ transform.changeType }}* - {{ transform.customerName }}\nPlan: {{ transform.oldPriceId }} -> {{ transform.newPriceId }}\nMRR change: ${{ transform.delta }}/mo (now ${{ transform.newMrr }}/mo)"
}
If you want the channel to differ by outcome (for example churn alerts going to #churn-risk), place a send-message node on each Condition branch with the right channel and wording. To later look up who owns the account, the same connector exposes lookup-user-by-email, which you can use to mention the account manager by Slack user.
Step 6: Move the account's CRM card in Monday.com
Add a Connector node on the monday connector in Direct mode and select the update-item tool to keep the deal stage in sync. Identify the account's item on your board (store the Monday item id against the Stripe customer in advance, or first call list-items to find it), then write the new stage and MRR into the relevant columns:
{
"boardId": "1234567890",
"itemId": "{{ accountItemId }}",
"columnValues": {
"status": "{{ transform.changeType == 'churn' ? 'Churned' : (transform.changeType == 'upgrade' ? 'Expansion' : 'Active') }}",
"numbers_mrr": "{{ transform.newMrr }}"
}
}
Add a brief audit note with the create-update tool on the same connector so the timeline shows what happened: include the plan change and the MRR delta. Running the Slack and Monday.com steps as two separate Connector nodes keeps each side independently retryable. If you would rather run them at the same time, wrap both in a Parallel node so a slow Slack post does not delay the CRM update.
Tips
- Stripe amounts are integers in the smallest unit. Always divide
unit_amountby 100 (or your currency's factor) before comparing, or your MRR delta will be off by 100x. - Use Miraxa, the intelligent layer across your automation, to scaffold the branches: try "Add a Condition node that checks if
{{ transform.changeType }}is churn and connect the true branch to a Slack send-message node," then fine-tune fields in the properties panel. - For multi-item subscriptions, the first item is not always the plan you bill on. Match by your known plan price ids in the Transform step rather than assuming index
0. - Keep the price-id to MRR lookup in the Transform node so adding a new plan is a one-line edit, not a workflow rebuild.
Common Pitfalls
- Missing the diff:
previous_attributesonly contains fields that actually changed, and it is absent oncustomer.subscription.deleted. Guard for missing keys in the Transform node so churn events do not error. - Webhook replays: Stripe retries delivery until it gets a success response. Without dedup on the event id, a single change can post several Slack alerts. Turn on event-id dedup in the Webhook trigger.
- Signature failures: if events never arrive, confirm the signing connection matches the Stripe endpoint's signing secret. A mismatch is silently rejected before
{{ input }}is ever populated. - Stale card lookups: if you search Monday.com by name with
list-items, renamed accounts will not match. Store the Monday item id keyed to the Stripe customer id so the move is exact and idempotent.
Testing
Validate on a sandbox before going live. Point the Webhook trigger at a Stripe test-mode endpoint and use Stripe's dashboard to send a test customer.subscription.updated event, or change a plan on a test subscription. Open the run in execution history and confirm the Transform node produced the right changeType and delta, then check that Slack posted once and the Monday.com item landed in the expected group. Send a customer.subscription.deleted event next to verify the churn path. Once both branches behave on a test customer and a quantity-only edit is correctly dropped as no-change, enable the workflow against your live Stripe endpoint.
Learn More
- Trigger node and webhook setup in the Spojit developer docs.
- Stripe connector reference for the full tool catalog.
- Monday.com connector reference for board and item fields.
- How to Send Slack Alerts for Subscription Payment Events for a related payment-event pattern.
- Using Connector Nodes in Direct Mode to map tool inputs precisely.
- Using Condition Nodes for branching on the change type.