Fetch all Patreon members with email via GET /api/oauth2/v2/campaigns/{id}/members?fields[member]=full_name,email,patron_status,currently_entitled_amount_cents&include=currently_entitled_tiers, paginate via links.next cursor, then segment active/declined/former patrons into your ESP (Mailchimp, ConvertKit, Beehiiv). Critical: without the campaigns.members[email] scope, the email field is silently absent — no error, just missing data.
| Fact | Value |
|---|---|
| Platform | Patreon |
| Rate limits | Undisclosed; 4xx circuit breaker: 2,000 bad requests in 10 min = 30-min block |
| Difficulty | Intermediate |
| Time required | 60 minutes |
| Last updated | May 2026 |
API Quick Reference
Undisclosed; 4xx circuit breaker: 2,000 bad requests in 10 min = 30-min block
REST only
Patreon to ESP Sync Overview
Patreon provides membership and pledge data that maps directly to email marketing segmentation. Syncing this data to your ESP enables tier-based email sequences, win-back campaigns for declined patrons, and sunset flows for former patrons. The sync runs daily to keep segments current as patrons upgrade, downgrade, or churn.
https://www.patreon.com/api/oauth2/v2OAuth2 Scopes Required for Email Sync
- 1Create your OAuth client at patreon.com/portal/registration/register-clients
- 2Request these scopes: campaigns.members and campaigns.members[email]
- 3campaigns.members[email] is a separate sensitive scope — request it explicitly
- 4Use the Creator's Access Token for your own campaign (no OAuth dance needed)
- 5If building for other creators: implement the full OAuth2 authorization code flow
- 6Always include User-Agent header — missing it returns 403 with no explanation
Key endpoints
/api/oauth2/v2/campaignsList all campaigns for the authenticated creator. Returns campaign IDs needed for the members endpoint.
Response
1{"data":[{"id":"12345","type":"campaign","attributes":{"creation_name":"My Podcast","patron_count":842}}]}/api/oauth2/v2/campaigns/{campaign_id}/membersFetch all campaign members with email and tier data. Requires campaigns.members scope (and campaigns.members[email] for email access).
/api/oauth2/v2/webhooksRegister a webhook to receive real-time member updates (create, update, delete) instead of polling.
Response
1{"data":{"id":"67890","type":"webhook","attributes":{"triggers":["members:create","members:update","members:delete"],"uri":"https://yourapp.com/api/patreon-webhook"}}}Step-by-step automation
Fetch All Members with Email and Tier Data
Why: The full member list is the source of truth for ESP segmentation. Without pagination, you only get the first 1,000 members — leaving hundreds unsynced for large campaigns.
Fetch all campaign members including email (requires campaigns.members[email] scope) and tier relationships. Paginate via links.next cursor.
1export PATREON_TOKEN="your_creator_token"2export CAMPAIGN_ID="your_campaign_id"34curl -s \5 -H "Authorization: Bearer $PATREON_TOKEN" \6 -H "User-Agent: EspSync (admin@yourapp.com)" \7 "https://www.patreon.com/api/oauth2/v2/campaigns/$CAMPAIGN_ID/members?fields[member]=full_name,email,patron_status,currently_entitled_amount_cents,last_charge_status&include=currently_entitled_tiers&fields[tier]=title,amount_cents&page[count]=1000" \8 | python3 -m json.tool | head -80Segment Members by Status and Tier
Why: Active, declined, and former patrons need different ESP treatment. Active patrons get tier-specific content. Declined get a win-back sequence. Former patrons should be removed from active lists to maintain deliverability.
Segment the member list by patron_status and currently_entitled_tiers. Build separate lists for each segment to sync to the ESP.
1# Not applicable — segmentation is programmaticUpsert Active Patrons to ESP with Tier Tags
Why: Upsert (update-or-create) ensures contacts stay current when patrons change tiers. Using tags for tier names enables conditional sending logic in your ESP.
Sync active patrons to your ESP with tags representing their tier(s). This example shows Mailchimp — the same pattern applies to ConvertKit (tags) and Beehiiv (segments).
1# Mailchimp upsert a single contact to an audience2export MC_API_KEY="your_mailchimp_api_key"3export MC_LIST_ID="your_audience_id"4export MC_SERVER="us1" # e.g., us1, us2, us356curl -s -X PUT \7 -H "Authorization: Bearer $MC_API_KEY" \8 -H "Content-Type: application/json" \9 -d '{10 "email_address": "patron@example.com",11 "status_if_new": "subscribed",12 "merge_fields": {"FNAME": "Jane", "PATRONAMT": "5.00"},13 "tags": ["Gold Tier", "Active Patron"]14 }' \15 "https://$MC_SERVER.api.mailchimp.com/3.0/lists/$MC_LIST_ID/members/$(echo -n 'patron@example.com' | md5sum | cut -d' ' -f1)"Handle Declined and Former Patrons
Why: Declined patrons with a failed payment need a different message than active ones — usually a win-back or payment update sequence. Former patrons should leave active segments to protect deliverability.
Tag declined patrons for win-back sequences and remove former patrons from active segments. Handle the last_charge_status field to distinguish recoverable declines from permanent cancellations.
1# Tag a contact as 'Declined Patron' in Mailchimp by PATCH-ing member tags2curl -s -X POST \3 -H "Authorization: Bearer $MC_API_KEY" \4 -H "Content-Type: application/json" \5 -d '{"tags": [{"name": "Declined Patron", "status": "active"}, {"name": "Active Patron", "status": "inactive"}]}' \6 "https://$MC_SERVER.api.mailchimp.com/3.0/lists/$MC_LIST_ID/members/EMAIL_HASH/tags"Complete working code
Complete Patreon to Mailchimp segment sync. Fetches all members with email, segments by patron status, upserts to Mailchimp with tier tags, and handles declined/former patrons.
Error handling
The campaigns.members[email] scope was not requested or authorized. Without it, Patreon silently omits the email field — no error is thrown.
Re-register your OAuth client to include campaigns.members[email] scope. Then re-authorize using the OAuth2 flow (or regenerate the Creator's Access Token with the new scope). This is the most common Patreon ESP sync issue.
Missing User-Agent header or missing campaigns.members scope.
Add User-Agent: YourApp (contact@yourapp.com) to every request. Verify the campaigns.members scope is included in your token's scope set.
Not paginating via links.next cursor — only fetching the first page.
Always check for data.links.next in each response and continue fetching until no next link exists. Set page[count]=1000 for maximum efficiency.
A patron changed their Patreon email between syncs, creating two ESP contacts.
Always use upsert operations (PUT in Mailchimp, not POST) with the email hash as the key. Clean up old contacts by running a deduplication pass when the sync total drops unexpectedly.
Patreon's undisclosed rate limits or the 4xx circuit breaker triggered during development with malformed requests.
Add 500ms delays between page requests. If the circuit breaker fired (2,000+ 4xx responses), wait 30 minutes. Fix all 4xx issues before running again.
Rate Limiting for Patreon Member Sync
| Scope | Limit | Window |
|---|---|---|
Security checklist
- Store PATREON_TOKEN and MAILCHIMP_API_KEY in environment variables
- The campaigns.members[email] scope provides access to patron email addresses — handle per GDPR/CCPA
- Disclose Patreon-to-ESP data sharing in your privacy policy
- Do not log email addresses in plain text in production logs
- Implement data retention limits — remove former patron emails after 12 months of inactivity
Automation use cases
Daily Tier-Based Segmentation
Run daily to maintain accurate tier segments in Mailchimp/ConvertKit. Patrons who upgrade get additional tags; downgrades remove the higher-tier tags.
Declined Patron Win-Back Campaign
Detect declined_patron status and trigger a 3-email win-back sequence reminding them to update their payment method on Patreon.
Former Patron Re-Engagement
Add former patrons to a sunset segment. After 30 days, trigger a discounted re-join offer. After 90 days without response, remove from all active segments.
Best practices
- Always specify fields[member]=email,... explicitly — without it, email is absent from responses with no error
- Add User-Agent header on every request — omitting it returns 403 that looks like an auth error
- Handle all three patron_status values: active, declined, and former — leaving declined patrons in active segments hurts email deliverability
- Use upsert operations in your ESP rather than create-or-skip to keep data current as patrons change tiers
- Add 500ms delays between Patreon pagination requests to stay safely within undisclosed rate limits
- Run the sync daily in the early morning hours — most patron status changes occur during Patreon's monthly billing cycle
- Log sync counts and check for anomalies — a sudden 20% drop in synced contacts likely means a scope or API issue
Ask AI to help
Copy one of these prompts to get a personalized, working implementation.
I'm building a Patreon to ConvertKit segment sync automation. I fetch all Patreon members with campaigns.members[email] scope, segment by patron_status (active/declined/former), and sync to ConvertKit using their API v4. Active patrons get tagged with their tier name. Declined patrons get a 'Win Back' tag. Former patrons have all Patreon tags removed. Can you help me implement the ConvertKit upsert using PUT /v4/subscribers/{id} and handle the case where the subscriber doesn't exist yet (create with POST /v4/subscribers)?
Frequently asked questions
Why are all my member contacts missing email addresses?
You're missing the campaigns.members[email] scope. Without it, Patreon silently omits the email field from all member responses — no 403, no error message, just an absent field. Regenerate your OAuth client with this scope explicitly requested and re-authorize. This is the #1 issue reported when building Patreon ESP syncs.
How do I get the campaign ID for the members endpoint?
Call GET /api/oauth2/v2/campaigns with your Creator's Access Token. The response includes your campaign's ID. For a creator with one campaign, this is a one-time lookup — store the ID as a constant rather than fetching it every sync run.
Should I remove former patrons from my email list entirely?
Don't unsubscribe them immediately — they're a warm audience. Instead, move them to a 'Former Patron' segment and run a re-engagement campaign over 30-90 days. Only unsubscribe (or suppress) if they haven't re-subscribed after your re-engagement attempt or if they explicitly unsubscribe from your ESP.
How do I handle patrons who change tiers?
The daily sync handles tier changes automatically — the members endpoint always returns currently_entitled_tiers. On the ESP side, upsert the contact with the updated tier tags. In Mailchimp, use the member PUT endpoint which overwrites existing tag state when you include the tags array.
What's the difference between declined_patron and former_patron?
A declined_patron had a payment failure — their card was declined, expired, or insufficient funds. They haven't cancelled; they may recover. A former_patron has explicitly cancelled their pledge or had their membership removed. Treat declined as recoverable (win-back sequence), former as churned (re-engagement or sunset).
Can I sync to ConvertKit instead of Mailchimp?
Yes. ConvertKit uses tags rather than list segments. After fetching Patreon members, use ConvertKit's POST /v4/subscribers endpoint to create or update subscribers, adding tags like 'Active Patron', 'Gold Tier', etc. ConvertKit's API v4 uses an API key (CONVERTKIT_API_KEY) in the Authorization header.
How often should I run the sync?
Daily is appropriate for most campaigns. Patreon's billing cycle is monthly, so member status changes are concentrated around billing dates. Running more frequently adds API load without significant benefit. For real-time new-member onboarding, use the members:create webhook in addition to the daily full sync.
Need this automated?
Our team has built 600+ apps with API automations. We can build this for you.
Book a free consultation