Stitchflow
Mailchimp logo

Mailchimp User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 6, 2026

Summary and recommendation

Mailchimp's Marketing API (v3.0) manages audience members - subscribers, contacts, tags, and merge fields - not account-level team seats. There is no API endpoint for adding, removing, or listing Mailchimp account users; that surface is UI-only.

Authentication is either HTTP Basic Auth with an API key (full account access, no scope restriction) or OAuth 2.0 (token inherits the authorizing user's permissions). The data center prefix is account-specific and must be resolved from the API key suffix or the OAuth metadata endpoint before constructing any request URL.

When building an identity graph across your SaaS stack, note that Mailchimp's API exposes subscriber identity data - email, merge fields, tags, engagement stats, opt timestamps - but provides no programmatic hook into account-level IAM.

API quick reference

Has user APIYes
Auth methodAPI Key (HTTP Basic Auth with 'anystring:<apikey>') or OAuth 2.0
Base URLOfficial docs
SCIM availableNo

Authentication

Auth method: API Key (HTTP Basic Auth with 'anystring:') or OAuth 2.0

Setup steps

  1. API Key: Log in to Mailchimp → Account → Extras → API Keys → Create A Key. Use as password in HTTP Basic Auth with any string as username (e.g., 'key:').
  2. OAuth 2.0: Register an app at https://admin.mailchimp.com/account/oauth2/ to obtain client_id and client_secret.
  3. OAuth 2.0: Redirect user to https://login.mailchimp.com/oauth2/authorize?response_type=code&client_id=&redirect_uri=.
  4. OAuth 2.0: Exchange authorization code for access token via POST to https://login.mailchimp.com/oauth2/token.
  5. OAuth 2.0: Call GET https://login.mailchimp.com/oauth2/metadata to retrieve the user's data center (dc) prefix for constructing the base URL.
  6. Use the dc prefix (e.g., 'us1') to build all API calls: https://us1.api.mailchimp.com/3.0/...

Required scopes

Scope Description Required for
N/A (API Key) API keys grant full account access; no granular scope selection available for API keys. All operations when using API key auth
OAuth 2.0 (no named scopes) Mailchimp OAuth 2.0 does not expose granular named scopes; the granted token has access equivalent to the authorizing user's account permissions. All operations when using OAuth 2.0

User object / data model

Field Type Description On create On update Notes
id string MD5 hash of the lowercase version of the list member's email address auto-generated immutable Used as the path parameter for member endpoints
email_address string The member's email address required optional Must be unique per list
status string (enum) Subscription status: subscribed, unsubscribed, cleaned, pending, transactional required optional Use 'pending' to trigger double opt-in
merge_fields object Key-value pairs for merge tags (e.g., FNAME, LNAME, PHONE) optional optional Merge tag names are list-specific and configurable
interests object Map of interest category IDs to boolean values indicating group membership optional optional Interest IDs must be retrieved from the list's interest categories endpoint
language string ISO 639-1 language code for the subscriber optional optional
vip boolean Whether the member is marked as VIP optional optional
location object Subscriber location data: latitude, longitude, gmtoff, dstoff, country_code, timezone optional optional Geo data may be auto-populated by Mailchimp from email open data
tags array Array of tag objects ({id, name}) associated with the member optional managed via separate /tags endpoint Tags are managed via POST /lists/{list_id}/members/{subscriber_hash}/tags
timestamp_signup string (ISO 8601) Date and time the subscriber signed up optional read-only after set
timestamp_opt string (ISO 8601) Date and time the subscriber confirmed opt-in read-only read-only Set automatically by Mailchimp
last_changed string (ISO 8601) Date and time of the last change to the member record read-only read-only
email_type string (enum) Email format preference: html or text optional optional
stats object Engagement stats: avg_open_rate, avg_click_rate read-only read-only
source string How the member was added (e.g., 'API', 'Admin Add', 'Import') read-only read-only
unique_email_id string A unique identifier for the email address across all Mailchimp lists read-only read-only
web_id integer The ID used in the Mailchimp web application read-only read-only
unsubscribe_reason string Reason provided when a member unsubscribes read-only read-only

Core endpoints

List all members in an audience

  • Method: GET
  • URL: https://<dc>.api.mailchimp.com/3.0/lists/{list_id}/members
  • Watch out for: Max count per request is 1000. Use offset pagination for large lists. Response includes only fields requested via 'fields' param if specified.

Request example

GET /3.0/lists/abc123/members?count=100&offset=0
Authorization: Basic base64(anystring:apikey)

Response example

{
  "members": [{"id":"md5hash","email_address":"user@example.com","status":"subscribed"}],
  "total_items": 500
}

Get a specific member

  • Method: GET
  • URL: https://<dc>.api.mailchimp.com/3.0/lists/{list_id}/members/{subscriber_hash}
  • Watch out for: subscriber_hash must be the MD5 hash of the lowercased email address, not the raw email.

Request example

GET /3.0/lists/abc123/members/md5(lowercase(email))
Authorization: Basic base64(anystring:apikey)

Response example

{
  "id": "8a6f2e3b...",
  "email_address": "user@example.com",
  "status": "subscribed",
  "merge_fields": {"FNAME":"Jane","LNAME":"Doe"}
}

Add or update a member (upsert)

  • Method: PUT
  • URL: https://<dc>.api.mailchimp.com/3.0/lists/{list_id}/members/{subscriber_hash}
  • Watch out for: Use 'status_if_new' (not 'status') to avoid accidentally resubscribing unsubscribed members on update. PUT replaces the full record; use PATCH for partial updates.

Request example

PUT /3.0/lists/abc123/members/md5hash
{
  "email_address": "user@example.com",
  "status_if_new": "subscribed",
  "merge_fields": {"FNAME":"Jane"}
}

Response example

{
  "id": "8a6f2e3b...",
  "email_address": "user@example.com",
  "status": "subscribed"
}

Update a member (partial)

  • Method: PATCH
  • URL: https://<dc>.api.mailchimp.com/3.0/lists/{list_id}/members/{subscriber_hash}
  • Watch out for: PATCH only updates provided fields. merge_fields object is merged at the key level, not replaced entirely.

Request example

PATCH /3.0/lists/abc123/members/md5hash
{
  "merge_fields": {"FNAME":"Janet"},
  "language": "en"
}

Response example

{
  "id": "8a6f2e3b...",
  "email_address": "user@example.com",
  "status": "subscribed",
  "merge_fields": {"FNAME":"Janet"}
}

Add a new member

  • Method: POST
  • URL: https://<dc>.api.mailchimp.com/3.0/lists/{list_id}/members
  • Watch out for: Returns HTTP 400 if the email already exists in the list. Use PUT for upsert behavior instead.

Request example

POST /3.0/lists/abc123/members
{
  "email_address": "new@example.com",
  "status": "subscribed",
  "merge_fields": {"FNAME":"John","LNAME":"Smith"}
}

Response example

{
  "id": "a1b2c3d4...",
  "email_address": "new@example.com",
  "status": "subscribed"
}

Archive (soft-delete) a member

  • Method: DELETE
  • URL: https://<dc>.api.mailchimp.com/3.0/lists/{list_id}/members/{subscriber_hash}
  • Watch out for: DELETE archives the member (removes from active count) but does not permanently delete. To permanently delete, use POST /lists/{list_id}/members/{subscriber_hash}/actions/delete-permanent.

Request example

DELETE /3.0/lists/abc123/members/md5hash
Authorization: Basic base64(anystring:apikey)

Response example

HTTP 204 No Content

Batch subscribe/unsubscribe members

  • Method: POST
  • URL: https://<dc>.api.mailchimp.com/3.0/lists/{list_id}
  • Watch out for: Limited to 500 members per request. 'update_existing: true' is required to update existing members; otherwise existing emails are silently skipped.

Request example

POST /3.0/lists/abc123
{
  "members": [{"email_address":"a@x.com","status":"subscribed"},{"email_address":"b@x.com","status":"unsubscribed"}],
  "update_existing": true
}

Response example

{
  "new_members": [...],
  "updated_members": [...],
  "errors": [],
  "total_created": 1,
  "total_updated": 1
}

Update member tags

  • Method: POST
  • URL: https://<dc>.api.mailchimp.com/3.0/lists/{list_id}/members/{subscriber_hash}/tags
  • Watch out for: Tags are created automatically if they don't exist. Set status to 'inactive' to remove a tag. There is no GET endpoint to list all account-level tags directly from this path.

Request example

POST /3.0/lists/abc123/members/md5hash/tags
{
  "tags": [{"name":"VIP","status":"active"},{"name":"OldTag","status":"inactive"}]
}

Response example

HTTP 204 No Content

Rate limits, pagination, and events

  • Rate limits: Mailchimp enforces a concurrent connection limit per API key rather than a per-minute request cap. The default is 10 simultaneous connections. Batch operations are recommended for bulk work.
  • Rate-limit headers: No
  • Retry-After header: No
  • Rate-limit notes: HTTP 429 is returned when the concurrent limit is exceeded. No standard Retry-After header is documented. Batch endpoint (POST /3.0/batches) is recommended to reduce concurrent connection usage.
  • Pagination method: offset
  • Default page size: 10
  • Max page size: 1000
  • Pagination pointer: offset and count
Plan Limit Concurrent
All paid plans 10 concurrent connections per API key 10
Free plan 10 concurrent connections per API key 10
  • Webhooks available: Yes
  • Webhook notes: Mailchimp supports list-level webhooks that fire on subscriber events. Webhooks are configured per audience (list) via the API or the Mailchimp dashboard. Mailchimp sends an HTTP POST to the configured URL.
  • Alternative event strategy: Mailchimp Transactional (Mandrill) has its own separate webhook system for transactional email events.
  • Webhook events: subscribe, unsubscribe, profile, cleaned, upemail, campaign

SCIM API status

  • SCIM available: No
  • SCIM version: Not documented
  • Plan required: Not documented
  • Endpoint: Not documented

Limitations:

  • Mailchimp does not offer a native SCIM 2.0 endpoint as of the current documentation review.
  • SCIM-like provisioning is available only via third-party IdP integrations (Okta, OneLogin, miniOrange) using those providers' Mailchimp app connectors, which map to Mailchimp's Marketing API under the hood.
  • The context reference to 'Enterprise' SCIM may reflect third-party connector availability rather than a native Mailchimp SCIM endpoint.
  • SSO (SAML) is available via third-party providers but is not natively built into Mailchimp's platform.

Common scenarios

Three integration patterns cover the majority of production use cases. For CRM-to-audience sync, use PUT /3.

0/lists/{list_id}/members/{subscriber_hash} with status_if_new rather than status - using status on a PUT will silently overwrite the status of already-unsubscribed contacts, creating CAN-SPAM and GDPR exposure.

For bulk operations exceeding 500 records, bypass the batch list endpoint and use the async Batch Operations API (POST /3. 0/batches) instead; always inspect the errors array in the response.

For event-driven subscriber intake, register list-level webhooks via POST /3. 0/lists/{list_id}/webhooks - payloads arrive as form-encoded POST bodies, not JSON, and the registration handshake requires the endpoint to return HTTP 200 to an initial GET verification request.

Sync CRM contacts to a Mailchimp audience

  1. Retrieve the target list_id via GET /3.0/lists.
  2. For each contact, compute subscriber_hash = MD5(lowercase(email)).
  3. Use PUT /3.0/lists/{list_id}/members/{subscriber_hash} with 'status_if_new': 'subscribed' and relevant merge_fields.
  4. For batches > 1, prefer POST /3.0/lists/{list_id} (batch endpoint, max 500/call) or POST /3.0/batches for async bulk operations.
  5. Check the 'errors' array in the batch response and log any failed records for retry.

Watch out for: Using 'status' instead of 'status_if_new' in PUT will overwrite the status of already-unsubscribed contacts, violating CAN-SPAM/GDPR compliance.

Unsubscribe a user and record the reason

  1. Compute subscriber_hash = MD5(lowercase(email)).
  2. PATCH /3.0/lists/{list_id}/members/{subscriber_hash} with body: {"status": "unsubscribed"}.
  3. Optionally store the unsubscribe reason in a custom merge field via the same PATCH call.
  4. Confirm the update by checking the returned 'status' field in the response.

Watch out for: Mailchimp does not expose a free-text 'unsubscribe_reason' write field via the API; the field is read-only and populated only when the user self-unsubscribes via Mailchimp's own forms.

Listen for new subscribers via webhook

  1. Create a publicly accessible HTTPS endpoint that accepts POST requests.
  2. Register the webhook via POST /3.0/lists/{list_id}/webhooks with 'events': {'subscribe': true} and 'sources': {'user': true, 'api': true, 'admin': true}.
  3. Mailchimp will send a form-encoded POST to the URL on each subscribe event.
  4. Parse the 'data[email]', 'data[merges]', and 'data[list_id]' fields from the incoming payload.
  5. Respond with HTTP 200 within the timeout window to acknowledge receipt.

Watch out for: Mailchimp webhook payloads are form-encoded (application/x-www-form-urlencoded), not JSON. Mailchimp also sends a GET request to the webhook URL during registration to verify it is reachable - the endpoint must return HTTP 200 to GET as well.

Why building this yourself is a trap

Several API behaviors are non-obvious and cause silent data corruption if missed. The subscriber_hash parameter is the MD5 hash of the lowercased email address - not the raw email and not a Mailchimp-assigned UUID; passing the wrong value returns a 404 with no helpful error context.

DELETE /members/{hash} archives the contact rather than permanently deleting it; permanent deletion requires a separate POST to /actions/delete-permanent and is irreversible. Rate limiting is enforced as a concurrent connection cap (default 10 per API key), not a per-minute request rate - sequential queuing avoids 429s more reliably than backoff alone.

API keys carry full account-level access with no scope restriction; there is no mechanism to issue a read-only or audience-scoped key, which is a meaningful least-privilege gap for any integration that only needs read access.

Provisioning automation at scale requires a third-party IdP connector or a platform that wraps the Marketing API with broader identity graph coverage across your SaaS environment.

Automate Mailchimp workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 6, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

Abnormal Security logo

Abnormal Security

API Only
AutomationAPI only
Last updatedMar 2026

Abnormal Security is an enterprise email security platform focused on detecting and investigating threats such as phishing, account takeover (ATO), and vendor email compromise. It does not support SCIM provisioning, which means every app in your stack

ActiveCampaign logo

ActiveCampaign

API Only
AutomationAPI only
Last updatedFeb 2026

ActiveCampaign uses a group-based permission model: every user belongs to exactly one group, and all feature-area access (Contacts, Campaigns, Automations, Deals, Reports, Templates) is configured at the group level, not per individual. The default Adm

ADP logo

ADP

API Only
AutomationAPI only
Last updatedFeb 2026

ADP Workforce Now is a mid-market to enterprise HCM platform that serves as the HR source of record for employee data — payroll, benefits, time, and talent. User access is governed by a hybrid permission model: predefined security roles (Security Maste