Hi everyone!
I built a small workflow that sends real-time Slack notifications whenever a Stripe payment succeeds. Sharing it here in case it’s useful.
The Problem
I was checking the Stripe dashboard multiple times a day just to see if payments came through. Wanted something that would just tell me automatically.
The Workflow
4 nodes, takes about 5 minutes to set up:
Stripe Trigger → Validate Event → Format Payment → Slack Notification
- Stripe Trigger: Catches payment_intent.succeeded webhook events
- Validate Event (Code node): Checks the event has valid data — rejects malformed webhooks
- Format Payment (Code node): Extracts amount, currency, customer email, payment ID, and timestamp into a clean message
- Slack Notification: Posts to your #payments channel
What You Need
- Stripe Secret Key (test or live)
- Slack Bot Token with chat:write scope
- A #payments channel in Slack
Workflow JSON
{“name”:“Stripe Payment Notifier — Slack (Free Version)”,“nodes”:[{“parameters”:{“events”:[“payment_intent.succeeded”]},“id”:“6726b5cb-727d-499d-90c3-2bce66a5ecc8”,“name”:“Stripe
Trigger”,“type”:“n8n-nodes-base.stripeTrigger”,“typeVersion”:1,“position”:[540,400],“webhookId”:“stripe-payment-notifier-free”},{“parameters”:{“mode”:“runOnceForEachItem”,“jsCode”:“const event =
$input.item.json;\nif (!event.type) throw new Error(‘Missing event type’);\nif (!event.data || !event.data.object) throw new Error(‘Missing event data.object’);\nconst obj = event.data.object;\nif (obj.amount
=== undefined && obj.amount_received === undefined) throw new Error(‘Missing amount’);\nreturn { json: event };”},“id”:“511bf16f-a504-4eb4-a77f-6bf5db507f6c”,“name”:“Validate Stripe
Event”,“type”:“n8n-nodes-base.code”,“typeVersion”:2,“position”:[820,400]},{“parameters”:{“mode”:“runOnceForEachItem”,“jsCode”:“const event = $input.item.json;\nconst obj = event.data.object;\nconst amount =
((obj.amount_received || obj.amount || 0) / 100);\nconst currency = (obj.currency || ‘usd’).toUpperCase();\nconst customerEmail = obj.receipt_email || obj.charges?.data?.[0]?.billing_details?.email ||
obj.metadata?.email || ‘No email’;\nconst paymentId = obj.id || ‘N/A’;\nconst created = obj.created ? new Date(obj.created * 1000).toISOString() : new Date().toISOString();\nreturn { json: { slack_message:
:white_check_mark: *Payment Received*\\n\\n*Amount:* ${amount.toFixed(2)} ${currency}\\n*Customer:* ${customerEmail}\\n*Payment ID:* \\${paymentId}\\\n*Date:* ${created} }
};”},“id”:“58424a2b-5cb7-45eb-9cfe-5832b9234b0e”,“name”:“Format
Payment”,“type”:“n8n-nodes-base.code”,“typeVersion”:2,“position”:[1100,400]},{“parameters”:{“select”:“channel”,“channelId”:{“__rl”:true,“mode”:“name”,“value”:“#payments”},“text”:“={{ $json.slack_message
}}”,“otherOptions”:{}},“id”:“0aa7293a-e030-4f5a-9e80-cbc97189d815”,“name”:“Slack: Payment Received”,“type”:“n8n-nodes-base.slack”,“typeVersion”:2.4,“position”:[1380,400]}],“connections”:{“Stripe
Trigger”:{“main”:[[{“node”:“Validate Stripe Event”,“type”:“main”,“index”:0}]]},“Validate Stripe Event”:{“main”:[[{“node”:“Format Payment”,“type”:“main”,“index”:0}]]},“Format Payment”:{“main”:[[{“node”:“Slack:
Payment Received”,“type”:“main”,“index”:0}]]}},“active”:false,“settings”:{“executionOrder”:“v1”}}
How to Import
- Copy the JSON above
- In n8n: Workflows → Import from File (or paste)
- Add your Stripe and Slack credentials
- Activate the workflow
- Test with Stripe test mode (sk_test_…)
Full Version
I also have a more complete version that handles subscriptions, failed charges, Google Sheets logging, Gmail notifications, and error handling with retries:
But the free version above covers the core use case — knowing instantly when someone pays you.
Let me know if you have questions or suggestions for improvement!