Someone pays for your Discord community at 11pm on a Tuesday. If you're asleep, they wait. If your payment notification goes unread, they wait longer. Some DM you. Some assume something went wrong. A few request a refund before you even see their name.
This is the Stripe + Discord integration problem in its simplest form. Here's how to fix it properly, including the parts most tutorials skip.
How the integration works
Stripe and Discord don't talk to each other natively. You connect them through n8n — an automation tool that sits between the two and handles the logic.
When a member pays, Stripe fires a webhook event to n8n. n8n reads the event, identifies the member, calls the Discord API to assign their role, and sends a welcome DM — all within 2 seconds of payment. When they cancel or a payment fails, the same chain runs in reverse.
The result: a member pays at any time of day or night and has full Discord access before they finish reading the payment confirmation email. You never touch it.
The Discord user ID problem — and how to solve it
This is where most integrations break, and it's worth understanding before you build anything.
Stripe knows your members by email address. Discord's API requires a user ID — a unique identifier that isn't their username or email. You need a mechanism that links a Stripe email to a Discord user ID before you can assign roles programmatically.
There are two clean approaches:
OAuth join flow — when a member completes payment, redirect them to a Discord OAuth page where they authorise your bot. This gives you their Discord user ID instantly and links it to their Stripe customer record. This is the approach we build as standard. It's the cleanest experience for the member and the most reliable mechanism.
Bot-assisted verification — your Discord bot DMs anyone who joins the server asking them to verify their email. When they reply, the bot looks up their Stripe record and links their Discord ID. This works but adds friction — the member has an extra step before they're fully onboarded.
Whichever approach you use, the linked ID needs to be stored somewhere your n8n workflow can retrieve on cancellation. Airtable, Google Sheets, or a database all work. Don't skip this — without it, you can't automate access removal.
The Stripe events to listen for
Set up your Stripe webhook to send these events to your n8n webhook URL:
checkout.session.completed— new member paid. Trigger onboarding.customer.subscription.deleted— subscription cancelled. Remove role.invoice.payment_failed— payment failed. Start dunning sequence.invoice.payment_succeeded— payment recovered. Restore access if in grace period.customer.subscription.updated— plan change. Swap roles if tiers differ.
Always verify the Stripe webhook signature in n8n. An unverified endpoint accepts requests from anyone. Your signing secret is in the Stripe dashboard under the webhook configuration — use it.
The onboarding flow, step by step
- Stripe fires
checkout.session.completedwebhook - n8n receives it, verifies the signature, extracts the customer email
- n8n looks up the Discord user ID from your member database using the email as the key
- n8n calls
PUT /guilds/{guild_id}/members/{user_id}/roles/{role_id}via HTTP Request node - n8n sends a personalised welcome DM via Discord bot
- n8n adds the member to your email onboarding sequence
- n8n logs the join in your member tracking sheet
Each step is a node in n8n. If any step fails, the error handler fires a Slack or email notification so you can intervene manually. No silent failures.
Failed payment handling
Don't remove access the moment a payment fails. Build a grace period — 3–5 days is standard.
When invoice.payment_failed fires: send a DM to the member in Discord and an email with a direct link to update their payment details. Set a wait node in n8n for 4 days. If the payment hasn't recovered by then (you check by calling the Stripe API), remove the role and trigger offboarding.
This approach recovers a meaningful percentage of lapsed members who had no intention of cancelling. One community we built this for recovered 18% of previously lost monthly revenue in the first 30 days of having the dunning sequence live.
Edge cases worth handling
Member doesn't join Discord after paying. Add a 24-hour wait in your onboarding flow. If the member still isn't in your server, send a follow-up email re-sending their invite link. Catches the people who got distracted or missed the original email.
Subscription upgrade. Listen for customer.subscription.updated and compare the previous and current plan. If the tier changed, remove the old role and assign the new one.
Refunds. Treat charge.refunded the same as a cancellation for access purposes — remove the role immediately.
Bot role hierarchy. Your bot's role in Discord must be positioned above any role it's trying to assign. Discord's permission model is strictly hierarchical — bots can only manage roles ranked below their own. Check this before testing; it's the most common setup mistake.
DIY or have it built
If you're comfortable with APIs and no-code tools, this integration takes 3–5 hours to set up in test mode and another hour to go live. The main sticking points are Discord bot permissions and the user ID mapping mechanism.
If you'd rather skip the learning curve, we can have your system live within a week of a scoping call. We build this as a standard setup and include the OAuth join flow, error handling, and member database as part of every project.