Mailchimp

Two nodes, one connected account. The action works on an audience — add or update a contact, set tags, drop someone into a Customer Journey, or look a contact up — and can also be an AI toolkit. The trigger fires a flow when something changes in an audience: a subscribe, an unsubscribe, a profile edit.

Connect an account

Both nodes use the same credential, and you connect it once. Click Connect Mailchimp in either node's credential picker, or from Settings → Credentials. Mailchimp asks you to pick which account to authorize and sends you back.

ℹMailchimp access tokens do not expire and there are no scopes to choose, so there is nothing to renew and nothing to re-approve later. The one thing HostWebhook stores alongside the token is your account's data centre — the us6 in us6.api.mailchimp.com. It is captured when you connect, which is why a credential saved before that step existed has to be reconnected.

The action node

Three operations that write and three that read. The Marketing API has 181 endpoints; these are the ones people actually automate.

Every operation that works on an audience asks you to pick it from the account's list — by name, with its contact count. For a flow that writes to different audiences, Type it instead takes an ID or a {{payload.x}}.

Add or update contact

Puts someone in an audience, or updates them if the email is already there. Point the email field at your incoming payload — {{payload.email}} is the usual answer — and Mailchimp takes the address itself, so there is no hashing to do.

⚠Status if new only applies to contacts that do not exist yet. Someone who already unsubscribed is never resubscribed by this node, no matter what you pick — HostWebhook sends Mailchimp's status_if_new field and never status, which is the one that would overwrite it.

The default is pending, which makes Mailchimp send its confirmation email. Choose subscribed only when you already have consent on record.

Merge fields are the audience's own fields — FNAME, LNAME and whatever else you defined in Mailchimp. List merge fields shows an audience's. Write one per line — FNAME: Ada — or as a JSON object:

{
  "FNAME": "{{payload.firstName}}",
  "LNAME": "{{payload.lastName}}"
}

Add or remove tags

Adding and removing happen in the same call. Write the tags comma-separated; a minus in front removes one:

customer, vip, -trial

That adds customer and vip and removes trial. A JSON list like [{"name":"trial","status":"inactive"}] still works — nodes set up that way keep running, and show it in the new form. The contact has to be in the audience already; if they are not, the error says so.

Tags belong to an audience, not to the account, so the same tag name in two audiences is two different tags.

Add contact to a journey

Drops an existing contact into a running Customer Journey at a specific step. The contact has to be in the journey's audience already — this operation enrols, it does not create. Pair it with Add or update contact when you need both.

The journey and step IDs come from the journey's Customer Journeys API starting point in Mailchimp: its URL ends in /journeys/{journey_id}/steps/{step_id}/actions/trigger.

Mailchimp only moves subscribed contacts through a journey. It accepts the call for a pending (unconfirmed) contact too, but the contact does not enter, so the output says "enrolled": false with the contact's contactStatus and the reason. The journey has to be turned on (Mailchimp asks for a paid plan to activate a flow), and it has to live in the Mailchimp account the credential is connected to: the trigger URL starts with that account's data centre, like https://us4.api.mailchimp.com. A journey from another account answers as if it did not exist.

Get contact, List audiences, List merge fields

Get contact looks someone up in an audience: status, merge fields and tags. Someone who is not there is not an error — the output says "found": false, so a Conditional can branch on it before you add them. List audiences returns the account's audiences with their IDs and contact counts; List merge fields, an audience's fields with their tag, type and whether they are required.


AI toolkit mode

Once the account is connected, the node asks for a Mode. AI toolkit turns it into six tools that an AI Node — or an MCP client, through one of your MCP servers — calls by name.

ToolArguments
upsert_contactaudience_id? · email · merge_fields? · language? · vip?
set_tagsaudience_id? · email · tags · skip_automations?
trigger_journeyjourney_id · step_id · email
get_mailchimp_contactaudience_id? · email
list_audiences—
list_merge_fieldsaudience_id?

When the node has an audience, audience_id can be left out and defaults to it. Tags go the same way as in the node: "vip, -trial".

What you control

  • Where the model can work. This node's audience (the default) keeps the model in one audience — the one you pick in the toolkit settings or, when empty, the Single operation's. Another audience is refused before Mailchimp is called, and list_audiences only shows that one. Any audience opens every audience of the account.
  • New contacts. The status a new contact gets is yours, not the model's: upsert_contact has no status argument. It is the same Status if new as above, pending by default, and an unsubscribed contact is never resubscribed.
  • Characters per call sent to the model. 20,000 by default, anything from 1,000 to 200,000.
  • Blocking tools. Nothing starts blocked. A journey can't be limited to one audience, so block trigger_journey under Block these tool calls if the agent shouldn't start one; block the three writes to make it read-only.

What goes back to the model

The same response as the operation. Lists that don't fit the characters limit are cut whole items at a time, with a notes field saying how many were left out. Arguments are used as written: a {{payload.x}} the model writes is not resolved against the flow.

Testing a tool

⚠Only a tool call picks the tool. In AI toolkit mode, only an AI Node, an MCP client or a voice agent chooses which tool the node runs. Run Test, a flow or a webhook run the operation saved on the node: an operation in their payload that names another tool is refused.
✦To try a tool, call it from an AI Node or from an MCP client. Its arguments look like this:
jsonA tool call
{ "operation": "get_mailchimp_contact", "email": "ada@example.com" }
⚠A node in toolkit mode is not part of the pipeline. Events arriving through connections made before you switched are refused — the node only runs the tool it is asked for.

The trigger

Pick Mailchimp as the service on a Trigger node. The configuration asks two things, in this order.

What fires it

Four buckets: subscribes and unsubscribes, profile changes, cleaned addresses (hard bounces and spam complaints), and campaign sent or cancelled. Each expands to Mailchimp's own event flags when the webhook is registered.

Which audience

⚠A Mailchimp webhook belongs to one audience, not to the account. To watch a second audience, add a second trigger — there is no account-wide setting to look for.

Every change counts

The trigger fires whoever caused the change: the contact themselves, an admin working in the Mailchimp dashboard, or an API call — including writes made by a HostWebhook Mailchimp action node. There is no switch to narrow this.

⚠Do not write to the audience you watch from the same flow. A Mailchimp action node updating a contact in that audience fires this trigger again, and every lap costs you an execution. Mailchimp does not say in the payload who caused the change, so a Filter cannot tell the two apart — keep the write in another audience or another flow.

What the trigger sends downstream

The common fields are flattened, and Mailchimp's raw body is kept whole under data so nothing is lost:

{
  "id": "8a25ff1d98:subscribe:2026-08-20 21:35:57",
  "event": "subscribe",
  "firedAt": "2026-08-20 21:35:57",
  "email": "ada@example.com",
  "contactId": "8a25ff1d98",
  "audienceId": "a6b5da1054",
  "merges": { "FNAME": "Ada", "LNAME": "Lovelace" },
  "action": null,
  "reason": null,
  "data": { "...": "the raw Mailchimp body" }
}

On an unsubscribe, action is unsub or delete and reason is manual or abuse — those two are what most flows branch on.

ℹThe id is not the contact id. Mailchimp reuses the same contact id across every event for that person, so a subscribe and a later unsubscribe would look like the same event and the second one would be dropped as a duplicate. HostWebhook combines contact, event type and timestamp instead.

Trying it out

The Test push button shows what a subscribe and an unsubscribe will look like: example payloads with the exact shape this trigger dispatches. They are examples, not your contacts — Mailchimp keeps no queryable history of webhook deliveries, so there is nothing past to fetch. To see a real one, activate the trigger and cause a real change: subscribing from your own signup form is the quickest.

Those two are the only events whose payload Mailchimp documents, so they are the only examples. The button needs Subscribes and unsubscribes among the events you picked; for profile changes, cleaned addresses and campaigns, the first real event is what shows you the shape.

Before that first event arrives, the node still shows the shape of a subscribe and an unsubscribe payload, so you can write {{payload.email}} in the nodes below it from the start.

✦The action node's Run test button is not a rehearsal: it runs the configured operation against your real Mailchimp account, and the three writes really write. Point them at a throwaway audience the first time — or start with Get contact, which only reads.

Good to know

Mailchimp allows 10 simultaneous connections per account and times requests out at 120 seconds. There is no published per-minute cap.

Webhooks do not expire, so nothing needs renewing. Deactivating the trigger deletes the webhook in Mailchimp; reactivating registers a fresh one.

ℹMailchimp Transactional (formerly Mandrill) is a different product with its own key and its own webhooks. These nodes do not talk to it.