Why Native Discord + Stripe Integration Doesn't Exist
Discord has no built-in payment layer. Stripe has no built-in Discord hook. Every paid Discord community on the internet is stitching these two together with something — a bot service, a middleware tool, or custom webhooks. The question is which approach actually works at scale without breaking, leaking access, or costing you $50+/month in SaaS fees.
This guide covers the direct webhook approach using n8n — the same setup we build for clients. It's free to self-host, handles every edge case, and gives you complete control over the logic.
What the Integration Needs to Handle
A production Stripe–Discord integration isn't just "give role when paid." It needs to cover the full membership lifecycle:
- Payment succeeded → grant Discord role immediately
- Subscription cancelled → remove role at period end
- Payment failed → trigger dunning sequence, remove role after grace period
- Subscription upgraded/downgraded → swap roles accordingly
- Refund issued → remove access immediately
- Member leaves Discord → log it, cancel Stripe subscription if needed
Tools like LaunchPass and Whop handle some of this but take 3–5% of revenue and lock you into their platform. The n8n approach costs nothing beyond hosting and gives you full control.
Architecture Overview
The integration has three layers:
- Stripe Webhooks — Stripe fires an event to your n8n URL every time something happens on a subscription
- 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 roles
The missing link most people struggle with: how does Stripe know a customer's Discord ID? You solve this at checkout — pass it as metadata when the Stripe checkout session is created, or collect it via a post-payment form and store it against the customer record.
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'll 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 — this is what you'll paste into your Stripe dashboard under Webhooks.
In Stripe, add a new endpoint with your n8n URL and 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
Inside your n8n workflow, add a Switch node that routes based on the incoming type field from Stripe:
- invoice.payment_succeeded → HTTP Request node → Discord API → Add role
- customer.subscription.deleted → HTTP Request node → Discord API → Remove role
- invoice.payment_failed → Set a wait period (3 days) → Remove role if still unpaid
The Discord API call to add a role looks like this:
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. You'll need to create a Discord bot in the Developer Portal and give it the Manage Roles permission in your server.
Step 4: Handle Multi-Tier Subscriptions
If you have multiple price tiers (e.g., Basic at £29/month, Pro at £79/month), map each Stripe Price ID to a specific Discord role in a lookup table 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
Stripe's dashboard has a webhook testing tool. Trigger test events for each type and verify the correct role action happens in your Discord server. Pay special attention to the payment_failed flow — this is where most integrations break. Set up a test customer with a card that fails (Stripe provides test card numbers for this) and confirm the grace period logic fires correctly.
Common Failure Points
- Discord user not found — the user left the server after subscribing. Your workflow needs to handle this gracefully, not crash.
- Bot role hierarchy — your bot's role must be higher in the server hierarchy than the role it's trying to assign. This trips up nearly everyone on first setup.
- Webhook signature verification — always verify Stripe's webhook signature in n8n to prevent spoofed events.
- Race conditions — two events firing simultaneously for the same customer. Add idempotency checks.
When to Use a Service Instead
This setup takes 3–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. When you hit £2,000+ MRR or need custom logic (multiple tiers, trial periods, cohort-based access), the custom webhook approach pays for itself quickly — no revenue percentage, no platform dependency.
ShipWorkflow builds and maintains this integration for paid community operators. If you want it done right without touching code, get in touch.