Stitchflow
Campaign Monitor logo

Campaign Monitor User Management API Guide

API workflow

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

UpdatedMar 4, 2026

Summary and recommendation

Campaign Monitor exposes a REST API at https://api.createsend.com/api/v3.3 supporting HTTP Basic Auth (API key as username, any non-empty string as password) and OAuth 2.0 for third-party integrations acting on behalf of other accounts.

The API covers subscriber lifecycle management, list operations, campaign creation, and client (sub-account) administration, but has no SCIM 2.0 endpoint and no documented identity provisioning surface.

For teams building automated provisioning pipelines across a broader tool stack, Stitchflow's MCP server with ~100 deep IT/identity integrations offers a faster path than assembling per-app API clients - Campaign Monitor included. The native API remains the right layer for subscriber-level automation within Campaign Monitor itself.

API quick reference

Has user APIYes
Auth methodHTTP Basic Auth with API key (API key as username, any string as password) or OAuth 2.0 for third-party integrations
Base URLOfficial docs
SCIM availableNo

Authentication

Auth method: HTTP Basic Auth with API key (API key as username, any string as password) or OAuth 2.0 for third-party integrations

Setup steps

  1. Log in to Campaign Monitor and navigate to Account Settings > API Keys.
  2. Generate or copy your API key.
  3. For direct API calls: use HTTP Basic Auth with the API key as the username and any non-empty string (e.g., 'x') as the password.
  4. For third-party app integrations: implement OAuth 2.0 authorization code flow using the Campaign Monitor OAuth endpoints to obtain an access token on behalf of a user.

Required scopes

Scope Description Required for
ViewReports Read access to campaign and list reports. Reading subscriber and campaign analytics
CreateCampaigns Ability to create and send campaigns. Campaign creation
SendCampaigns Ability to send campaigns. Sending campaigns
AddSubscribersToList Add or update subscribers on a list. Subscriber creation and updates
ImportSubscribers Bulk import subscribers. Bulk subscriber operations
ManageSubscribersForAllLists Manage subscribers across all lists. Cross-list subscriber management
AdministerAccount Full account administration including client management. Client/account-level user management

User object / data model

Field Type Description On create On update Notes
EmailAddress string Subscriber's email address (primary identifier). required required Used as the unique key for a subscriber within a list.
Name string Subscriber's full name. optional optional
Date string (ISO 8601) Date the subscriber was added to the list. system-set read-only Returned in responses; not settable on create.
State string Subscription state: Active, Unsubscribed, Bounced, Deleted, or Unconfirmed. system-set read-only Controlled by subscribe/unsubscribe actions.
CustomFields array of objects List of custom field key-value pairs for the subscriber. optional optional Each object has Key and Value properties. Fields must be pre-defined on the list.
ResubscribeBehavior string Controls behavior when adding an existing subscriber: OnlySubscribed, OnlyUnsubscribed, or AlwaysSubscribe. optional optional Used in add/update subscriber requests.
ConsentToTrack string Consent status for tracking: Yes, No, or Unchanged. required (in some regions) optional Required for GDPR compliance in applicable regions.
ListID string The ID of the list the subscriber belongs to. required (in URL) required (in URL) Passed as a URL path parameter, not in the body.

Core endpoints

Add or update a subscriber

  • Method: POST
  • URL: https://api.createsend.com/api/v3.3/subscribers/{listId}.json
  • Watch out for: If the subscriber already exists and Resubscribe is false, the call succeeds but the subscriber is not re-added.

Request example

POST /api/v3.3/subscribers/abc123.json
{
  "EmailAddress": "user@example.com",
  "Name": "Jane Doe",
  "ConsentToTrack": "Yes",
  "CustomFields": [{"Key": "City", "Value": "Sydney"}],
  "Resubscribe": true
}

Response example

"user@example.com"

Get subscriber details

  • Method: GET
  • URL: https://api.createsend.com/api/v3.3/subscribers/{listId}.json?email={email}
  • Watch out for: Email must be URL-encoded in the query string.

Request example

GET /api/v3.3/subscribers/abc123.json?email=user%40example.com

Response example

{
  "EmailAddress": "user@example.com",
  "Name": "Jane Doe",
  "Date": "2024-01-15 10:00:00",
  "State": "Active",
  "CustomFields": [{"Key": "City", "Value": "Sydney"}]
}

Unsubscribe a subscriber

  • Method: POST
  • URL: https://api.createsend.com/api/v3.3/subscribers/{listId}/unsubscribe.json
  • Watch out for: This unsubscribes from the specific list only, not globally.

Request example

POST /api/v3.3/subscribers/abc123/unsubscribe.json
{
  "EmailAddress": "user@example.com"
}

Response example

HTTP 200 OK (empty body)

Delete a subscriber

  • Method: DELETE
  • URL: https://api.createsend.com/api/v3.3/subscribers/{listId}.json?email={email}
  • Watch out for: Deletion is permanent and removes the subscriber from the list entirely.

Request example

DELETE /api/v3.3/subscribers/abc123.json?email=user%40example.com

Response example

HTTP 200 OK (empty body)

Bulk import subscribers

  • Method: POST
  • URL: https://api.createsend.com/api/v3.3/subscribers/{listId}/import.json
  • Watch out for: Maximum 1,000 subscribers per import request. Larger batches must be split.

Request example

POST /api/v3.3/subscribers/abc123/import.json
{
  "Subscribers": [
    {"EmailAddress": "a@example.com", "Name": "Alice", "ConsentToTrack": "Yes"},
    {"EmailAddress": "b@example.com", "Name": "Bob", "ConsentToTrack": "No"}
  ],
  "Resubscribe": true
}

Response example

{
  "TotalUniqueEmailsSubmitted": 2,
  "TotalExistingSubscribers": 0,
  "TotalNewSubscribers": 2,
  "DuplicateEmailsInSubmission": [],
  "FailureDetails": []
}

Get active subscribers for a list

  • Method: GET
  • URL: https://api.createsend.com/api/v3.3/lists/{listId}/active.json
  • Watch out for: Max page size is 1,000. Iterate pages using the page parameter.

Request example

GET /api/v3.3/lists/abc123/active.json?page=1&pagesize=1000&orderfield=email&orderdirection=asc

Response example

{
  "Results": [
    {"EmailAddress": "user@example.com", "Name": "Jane", "Date": "2024-01-15", "State": "Active"}
  ],
  "ResultsOrderedBy": "email",
  "TotalNumberOfRecords": 1,
  "PageNumber": 1,
  "PageSize": 1000
}

Create a client (sub-account)

  • Method: POST
  • URL: https://api.createsend.com/api/v3.3/clients.json
  • Watch out for: Requires AdministerAccount OAuth scope or account-level API key. Returns the new ClientID.

Request example

POST /api/v3.3/clients.json
{
  "CompanyName": "Acme Corp",
  "Country": "Australia",
  "TimeZone": "(GMT+10:00) Canberra, Melbourne, Sydney"
}

Response example

"a1b2c3d4e5f6"

Get client details

  • Method: GET
  • URL: https://api.createsend.com/api/v3.3/clients/{clientId}.json
  • Watch out for: Only accessible with account-level (agency) API key or appropriate OAuth scope.

Request example

GET /api/v3.3/clients/a1b2c3d4e5f6.json

Response example

{
  "BasicDetails": {
    "ClientID": "a1b2c3d4e5f6",
    "CompanyName": "Acme Corp",
    "Country": "Australia",
    "TimeZone": "(GMT+10:00) Canberra, Melbourne, Sydney"
  }
}

Rate limits, pagination, and events

  • Rate limits: Campaign Monitor enforces rate limits per API key. The documented limit is 1 request per second for most endpoints. Bulk import endpoints have separate limits.
  • Rate-limit headers: No
  • Retry-After header: No
  • Rate-limit notes: HTTP 429 is returned when the rate limit is exceeded. The API does not document explicit rate-limit response headers. Retry with exponential backoff is recommended.
  • Pagination method: offset
  • Default page size: 1000
  • Max page size: 1000
  • Pagination pointer: page, pagesize
Plan Limit Concurrent
All plans 1 request/second per API key 1
  • Webhooks available: Yes
  • Webhook notes: Campaign Monitor supports list-level webhooks that fire on subscriber lifecycle events. Webhooks are configured per list via the API or UI and POST a JSON payload to a specified URL.
  • Alternative event strategy: Polling the /lists/{listId}/active.json, /lists/{listId}/unsubscribed.json, and /lists/{listId}/bounced.json endpoints for changes.
  • Webhook events: Subscribe, Deactivate (Unsubscribe or Bounce), Update (subscriber details changed)

SCIM API status

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

Limitations:

  • Campaign Monitor does not offer a SCIM 2.0 API for identity provisioning.
  • No documented SAML SSO or SCIM support across any pricing tier.

Common scenarios

Three scenarios cover the majority of programmatic use cases:

  • Provisioning a subscriber: POST to /subscribers/{listId}.json with EmailAddress, Name, ConsentToTrack, and optional CustomFields. Set Resubscribe: true to reactivate previously unsubscribed contacts. Omitting ConsentToTrack in GDPR-applicable regions returns a 400 error.

  • Deprovisioning across lists: There is no global unsubscribe or delete endpoint. Retrieve all lists via GET /clients/{clientId}/lists.json, then call POST /subscribers/{listId}/unsubscribe.json or DELETE /subscribers/{listId}.json?email={email} per list. Confirm removal with a follow-up GET; expect a 404 or Deleted state.

  • Bulk import: POST batches of up to 1,000 records to /subscribers/{listId}/import.json. Inspect FailureDetails in the response for per-record errors. Batches exceeding 1,000 must be split - the API rejects larger payloads outright.

Provision a new subscriber to a list

  1. Obtain the target list ID from the Campaign Monitor UI or GET /clients/{clientId}/lists.json.
  2. POST to /subscribers/{listId}.json with EmailAddress, Name, ConsentToTrack, and any CustomFields.
  3. Set Resubscribe: true to re-activate previously unsubscribed contacts if needed.
  4. Check the response for the confirmed email address or handle 400 errors for validation failures.

Watch out for: If ConsentToTrack is omitted and the account is in a GDPR region, the request will fail with a 400 error.

Sync and deprovision a subscriber across lists

  1. Retrieve all lists for the client via GET /clients/{clientId}/lists.json.
  2. For each list, call POST /subscribers/{listId}/unsubscribe.json with the subscriber's email to unsubscribe them.
  3. Optionally call DELETE /subscribers/{listId}.json?email={email} to fully remove the record from each list.
  4. Verify removal by calling GET /subscribers/{listId}.json?email={email} and confirming a 404 or Deleted state.

Watch out for: Unsubscribe and delete must be performed per-list; there is no single global deprovision endpoint.

Bulk import subscribers from an external system

  1. Prepare subscriber data in batches of up to 1,000 records.
  2. POST each batch to /subscribers/{listId}/import.json with the Subscribers array and Resubscribe flag.
  3. Inspect the FailureDetails array in the response to identify and retry failed records.
  4. Use webhooks (Subscribe event) on the list to confirm successful additions in near-real-time.

Watch out for: Batches exceeding 1,000 subscribers must be split; the API will reject larger payloads.

Why building this yourself is a trap

The rate limit of approximately 1 request/second per API key with no rate-limit response headers creates silent backpressure: HTTP 429 is returned on breach, but without Retry-After guidance, callers must implement their own exponential backoff logic. At scale, cross-list deprovision loops (one API call per list per subscriber) will hit this ceiling quickly.

Subscriber deletion via the API is irreversible - there is no soft-delete or recoverable state. Client management endpoints (creating or reading sub-accounts) require an account-level API key, not a client-level key; using the wrong credential returns an auth error with no clear diagnostic.

OAuth 2.0 is mandatory for any integration acting on behalf of a third-party Campaign Monitor account, and the AdministerAccount scope must be explicitly requested - it is not bundled with narrower scopes.

Automate Campaign Monitor 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 4, 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