Connecting Stripe to Discord is how paid community operators replace manual role management with automatic access control. When someone pays via Stripe, they get their Discord role instantly. When they cancel or their payment fails, the role is removed on schedule. No manual checking, no delay, no ex-members keeping access they no longer paid for.
This guide covers the direct webhook approach using n8n -- the same setup we use for clients. It handles every edge case, costs around $20/month to run, and gives you full control over the logic.
Why a native Stripe Discord connection does not exist
Discord has no built-in payment layer. Stripe has no built-in Discord hook. Every paid Discord community is connecting these two tools with something in the middle: a third-party bot service, a middleware platform like LaunchPass or Whop, or custom webhooks. The custom webhook approach gives you no revenue percentage, no platform dependency, and full control over upgrade, downgrade, and failed payment logic.
What the integration needs to handle
A production Stripe to Discord integration is not just "assign role when paid." It needs to cover the full membership lifecycle:
- Payment succeeded: grant paid Discord role immediately
- Subscription cancelled: remove role at period end
- Payment failed: trigger dunning sequence, remove role after grace period
- Subscription upgraded or downgraded: swap roles accordingly
- Refund issued: remove access immediately
- Member leaves Discord: log it and cancel Stripe subscription if required
Architecture overview
The integration runs on three layers:
- Stripe webhooks: Stripe fires an event to your n8n URL every time a subscription changes
- n8n workflow: receives the event, extracts the customer's Discord ID, determines what action to take
- Discord API: n8n calls Discord's REST API to add or remove the correct role
The key sticking point for most builders: how does Stripe know a customer's Discord ID? You solve this at checkout by passing it as metadata when the Stripe checkout session is created, or collecting it via a post-payment form and storing it against the customer record in Airtable.
Step 1: Collect Discord IDs at checkout
When creating a Stripe Checkout Session, add a custom field to collect the buyer's Discord username or user ID:
custom_fields: [
{
key: 'discord_username',
label: { type: 'custom', custom: 'Your Discord Username' },
type: 'text'
}
]
Store this in Stripe customer metadata immediately. You will reference it in every subsequent webhook event for that customer.
Step 2: Set up the n8n webhook receiver
Create a new n8n workflow with a Webhook trigger node. Copy the webhook URL and paste it into your Stripe dashboard under Webhooks. Subscribe to these events:
- customer.subscription.created
- customer.subscription.deleted
- invoice.payment_succeeded
- invoice.payment_failed
- customer.subscription.updated
Step 3: Build the role assignment logic
Add a Switch node in n8n that routes based on the incoming type field from Stripe:
- invoice.payment_succeeded: HTTP Request node to Discord API to add the paid role
- customer.subscription.deleted: HTTP Request node to Discord API to remove the role
- invoice.payment_failed: Wait node for three days, then remove role if still unpaid
The Discord API call to assign a paid role:
PUT https://discord.com/api/guilds/{guild_id}/members/{user_id}/roles/{role_id}
Authorization: Bot YOUR_BOT_TOKEN
To remove a role, use DELETE instead of PUT.
Step 4: Handle multi-tier subscriptions
If you have multiple price tiers (for example, Basic at $29/month and Pro at $79/month), map each Stripe Price ID to a specific Discord role inside n8n. When a subscription event fires, extract the price ID, look up the correct role, and assign it. On upgrades, remove the old role and add the new one in the same workflow run.
Step 5: Test every event type
Use Stripe's webhook testing tool in the dashboard. Trigger test events for each type and verify the correct role action happens in your Discord server. Pay close attention to the payment_failed flow. Use Stripe's test card numbers to simulate a failed payment and confirm the grace period and removal logic fires correctly.
Common failure points
- Discord user not found: the user left the server after subscribing. Handle this gracefully in your workflow without crashing the execution.
- Bot role hierarchy: your bot's role must be higher in the server role list than the role it is trying to assign. This is the most common first-time setup error.
- Webhook signature verification: always verify Stripe's webhook signature in n8n to block spoofed events.
- Race conditions: two events firing simultaneously for the same customer. Add idempotency checks in your workflow logic.
When to use a platform instead
This setup takes 3 to 4 hours to build correctly and requires a running n8n instance. If you have under 50 members and want something live today, LaunchPass or Whop are reasonable starting points. Above $2,000 MRR or when you need custom logic for multiple tiers, trial periods, or cohort access, the custom webhook approach pays for itself quickly with no revenue percentage and no platform dependency.
Want this set up correctly without the trial and error? We do payment-to-access automation for paid communities in 7 days. Book a free audit.
Related: Paid community automation: the complete guide | Automate Discord roles for tiers and renewals | Handle renewals, failed payments and cancellations | Full Stripe Discord membership lifecycle