Mailchimp ExecModule
Overview
MailchimpModule connects ValkyrAI workflows to Mailchimp Marketing API 3.0 for audiences, members, member tags, campaigns, campaign content, send checklists, and explicitly confirmed campaign sends. It exposes 15 bounded operations through the native map I/O ExecModule ABI and keeps OAuth access tokens or API keys in a READY IntegrationAccount.
The official n8n Mailchimp integration and Mailchimp resource model informed the operation set. ValkyrAI adds a validated data-center host, encrypted IntegrationAccount boundary, bounded requests and responses, one-page pagination, credential redaction, safe-read-only retry, write reconciliation guidance, subscriber-hash normalization, and a mandatory send guard.
Usage
- Create a Mailchimp OAuth integration with only the audience and campaign access the workflow needs. For private internal workflows, a Mailchimp API key is also supported.
- Store the OAuth access token or API key only in the encrypted
apiKeyfield of a ValkyrAIIntegrationAccount; set its status toREADY. - Bind the account through
ExecModuleConfig.authConfig.integrationAccount. - Set
authModetooauth_bearer(preferred) orapi_key. - Set
serverPrefixto the account data-center prefix, such asus19; do not provide a URL. - Choose one operation and provide its conditional audience, member, campaign, payload, or filter fields.
- For list operations, pass
nextOffsetto a later execution only whenhasMoreistrue.
Inputs
| Name | Type | Required | Description | Constraints |
|---|---|---|---|---|
operation | string | Yes | Operation listed below. | Exact allowlist of 15 values. |
serverPrefix | string | Yes | Mailchimp data-center prefix. | Lowercase letters followed by digits, such as us19; not a URL. |
authMode | string | Yes | oauth_bearer or api_key. | Defaults to OAuth bearer. |
audienceId | string | Conditional | List/audience identifier. | 1–128 safe identifier characters. |
memberId | string | Conditional | Member email or subscriber hash. | A bounded email is normalized to MD5 of its lowercase form; a hash must be 32 lowercase hex characters. |
campaignId | string | Conditional | Campaign identifier. | 1–128 safe identifier characters. |
record | object | Conditional | Payload for mutations. | Non-empty, at most 100 top-level fields and 256 KiB serialized; credential-like top-level keys rejected. |
query | object | No | Resource-specific list filters. | At most 20 allowlisted scalar fields; values at most 2,048 characters. |
offset | integer | No | Zero-based collection offset. | 0–1,000,000; default 0. |
limit | integer | No | Provider page size. | 1–500; default 100. |
confirmSend | boolean | Conditional | Explicit send authorization. | Must be true for send_campaign. |
Operation-specific payload requirements:
upsert_memberrequiresemail_addressandstatus_if_new; consent status must reflect the real contact state.update_member_tagsrequires a non-emptytagsarray with no more than 100 entries.create_campaignrequirestype,recipients, andsettings.set_campaign_contentrequires at least one ofhtml,plain_text, ortemplate.send_campaignrequiresconfirmSend: trueand does not accept an implicit approval.
Outputs
| Name | Type | When present | Description |
|---|---|---|---|
status | string | Always | success or error. |
operation | string | Always | Normalized operation. |
resource | string | After validation | Account, audience, member, tag, campaign, content, checklist, or send family. |
data | object | Single/action success | Provider record or bounded action response. A successful HTTP 204 action returns an empty object. |
items | array | List success | One bounded Mailchimp page. |
count | integer | List success | Items returned in this page. |
hasMore | boolean | List success | Whether total_items indicates another page. |
nextOffset | integer | When another page exists | Offset for the next execution. |
httpStatus | integer | Provider response | Mailchimp HTTP status. |
attempts | integer | Provider call or error | HTTP attempts consumed. |
error | object | Failure | Redacted code, message, and retryable fields. |
Audience and campaign responses are classified restricted. Credentials and record values are not copied into progress logs.
IntegrationAccount Requirements
| Setting | Requirement |
|---|---|
| Provider | Mailchimp Marketing API 3.0 |
| Preferred authentication | OAuth 2 bearer token in IntegrationAccount.apiKey |
| Alternative authentication | Mailchimp API key in IntegrationAccount.apiKey, sent with HTTP Basic over TLS |
| Status | Exactly READY |
accountName | Human-readable Mailchimp account/integration identity |
| Relationship | ExecModuleConfig.authConfig.integrationAccount |
Mailchimp recommends OAuth 2 for integrations that access other users' accounts. Grant only the permissions needed to read or write audiences and campaigns. This module never puts the credential in URLs, records, query filters, examples, logs, or WorkflowState. OAuth initiation, callback, refresh, and marketplace enrollment remain outside version 1.0.0.
Configuration
Illustrative persisted configuration:
{
"version": "1.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:mailchimp-marketing"
},
"payloadConfig": {
"parameters": "{\"authMode\":\"oauth_bearer\",\"serverPrefix\":\"us19\",\"operation\":\"list_members\",\"audienceId\":\"a1b2c3\",\"limit\":100,\"query\":{\"status\":\"subscribed\"}}"
}
}
The relationship is symbolic. The generated IntegrationAccount owns the encrypted secret.
Operations
| Resource | Operation | Provider route | Behavior |
|---|---|---|---|
| Account | get_account | GET /3.0 | Read account root. |
| Audiences | list_audiences | GET /3.0/lists | One offset page. |
| Audiences | get_audience | GET /3.0/lists/{audienceId} | Read one audience. |
| Members | list_members | GET /3.0/lists/{audienceId}/members | One offset page. |
| Members | get_member | GET /3.0/lists/{audienceId}/members/{subscriberHash} | Read one member. |
| Members | upsert_member | PUT /3.0/lists/{audienceId}/members/{subscriberHash} | Add or update one member. |
| Member tags | update_member_tags | POST /3.0/lists/{audienceId}/members/{subscriberHash}/tags | Add/remove declared tags. |
| Campaigns | list_campaigns | GET /3.0/campaigns | One offset page. |
| Campaigns | get_campaign | GET /3.0/campaigns/{campaignId} | Read one campaign. |
| Campaigns | create_campaign | POST /3.0/campaigns | Create one campaign. |
| Campaigns | update_campaign | PATCH /3.0/campaigns/{campaignId} | Update one campaign. |
| Content | get_campaign_content | GET /3.0/campaigns/{campaignId}/content | Read content. |
| Content | set_campaign_content | PUT /3.0/campaigns/{campaignId}/content | Replace declared content fields. |
| Checklist | get_campaign_send_checklist | GET /3.0/campaigns/{campaignId}/send-checklist | Inspect readiness. |
| Send | send_campaign | POST /3.0/campaigns/{campaignId}/actions/send | Requires confirmSend=true. |
Audience deletion, permanent member deletion, batch jobs, webhooks, automations, templates, reports, scheduling, unscheduling, replication, test sends, conversations, e-commerce, and transactional email are deferred.
Errors and Failure Modes
| Failure | Cause | Retry guidance |
|---|---|---|
VALIDATION_ERROR | Missing/invalid prefix, ID, consent payload, tags, campaign fields, query, bound, or send confirmation. | Correct the request; no provider call was sent. |
INTEGRATION_ACCOUNT_REQUIRED | No bound secure account. | Bind the intended account. |
INTEGRATION_ACCOUNT_NOT_READY | Account status is not READY. | Repair or reauthorize the account. |
MAILCHIMP_HTTP_400/404 | Provider validation, nonexistent resource, or campaign not ready. | Correct identifiers, field shapes, audience/campaign state, or filters. |
MAILCHIMP_HTTP_401/403 | Invalid credential or insufficient access. | Reauthorize OAuth or rotate the API key with minimum required access. |
MAILCHIMP_HTTP_429 | Account rate limit. | Reads retry at most three total attempts and honor bounded numeric Retry-After; writes remain single-attempt. |
MAILCHIMP_HTTP_5xx / NETWORK_ERROR | Provider or transport failure. | Reads retry. Reconcile member, tag, campaign, content, or send state before manually retrying a write. |
RESPONSE_TOO_LARGE | Provider response exceeded 5 MiB. | Narrow fields, filters, or page size. |
| Identity mismatch | A requested audience/member/campaign returned a different id. | Treat as failure and verify provider compatibility. |
Errors are bounded to 500 characters and pass through credential redaction. A timed-out mutation may have reached Mailchimp, so automatic write replay is disabled.
Example
Upsert an explicitly opted-in contact:
{
"serverPrefix": "us19",
"operation": "upsert_member",
"audienceId": "a1b2c3",
"memberId": "ada@example.com",
"record": {
"email_address": "ada@example.com",
"status_if_new": "subscribed",
"status": "subscribed",
"merge_fields": {
"FNAME": "Ada",
"LNAME": "Lovelace"
}
}
}
Expected normalized result:
{
"status": "success",
"operation": "upsert_member",
"resource": "members",
"data": {
"id": "3e3417d7ef77d5932a6734b916515ed5",
"email_address": "ada@example.com",
"status": "subscribed"
},
"httpStatus": 200,
"attempts": 1
}
Notes
- Pagination: collection operations return one page. Use
nextOffsetonly whenhasMoreis true; the module never silently traverses every page. - Rate limits: Mailchimp can return HTTP
429. The module retries only safe reads, honors bounded numericRetry-After, and caps safe reads at three attempts. - API limits: Mailchimp documents
countup to 1,000; ValkyrAI intentionally caps pages at 500, request JSON at 256 KiB, and response JSON at 5 MiB. - Idempotency:
GETcalls are retry-safe. Member PUT is provider-addressed by subscriber hash but can still trigger automations; every mutation is single-attempt and requires reconciliation after ambiguous transport failure. - Consent:
status_if_newandstatusmust reflect real, provable contact consent. The module does not infer subscription permission. - Destructive behavior: permanent deletion is intentionally not exposed. Tag changes, campaign updates, content replacement, and campaign sending are externally visible side effects.
- Sending: check
get_campaign_send_checklistfirst.send_campaignrequiresconfirmSend=true, sends immediately, and is never automatically retried. - External verification: deterministic tests cover validation, URL construction, auth modes, subscriber hashing, payload mapping, pagination, rate-limit retry, write non-retry, redaction, send guarding, response identity, and annotation discovery. Live Mailchimp execution is deferred until a separately authorized provider account is supplied.
See the official Mailchimp Marketing API reference, methods and pagination guide, OAuth 2 guide, and the official n8n Mailchimp node source for the functional reference.