Mailchimp

Lightweight, dependency-free, in-memory fake of the Mailchimp Marketing API (v3.0) for testing code that uses the official @mailchimp/mailchimp_marketing Node.js client (and the language-agnostic Mailchimp Marketing REST API).

Default port: 4653

Quick start

Start the server:

import { MailchimpServer } from "./services/mailchimp/src/server.js";

const server = new MailchimpServer(4653);
await server.start();
// ... run your app/tests ...
await server.stop();

Point the real @mailchimp/mailchimp_marketing client at it. The client builds its host from the server prefix (https://<prefix>.api.mailchimp.com). Because the client constructs that host internally, override basePath on the underlying API config (or run behind a proxy / hosts entry) to target the parlel fake at http://127.0.0.1:4653/3.0:

const mailchimp = require("@mailchimp/mailchimp_marketing");

mailchimp.setConfig({
  apiKey: "parlel-us1",   // any non-empty key works (Basic auth)
  server: "us1",
});

// Point the generated client at the parlel fake:
mailchimp.config.basePath = "http://127.0.0.1:4653/3.0";

const pong = await mailchimp.ping.get();
// => { health_status: "Everything's Chimpy!" }

const list = await mailchimp.lists.createList({
  name: "Parlel Newsletter",
  permission_reminder: "You signed up at parlel.test",
  email_type_option: true,
  contact: { company: "parlel", address1: "1 Test St", city: "Testville", state: "CA", zip: "00000", country: "US" },
  campaign_defaults: { from_name: "parlel", from_email: "hello@parlel.test", subject: "", language: "en" },
});

await mailchimp.lists.addListMember(list.id, {
  email_address: "subscriber@parlel.test",
  status: "subscribed",
  merge_fields: { FNAME: "Test", LNAME: "User" },
});

Authentication

The official client authenticates with HTTP Basic auth (Authorization: Basic base64("anystring:apikey")). The fake accepts any non-empty Basic credential, and also accepts an OAuth2 Bearer token (Authorization: Bearer <token>). Requests with no credentials get a Mailchimp-shaped 401 API Key Invalid.

The client prefixes every request with /3.0. The fake accepts paths with or without the /3.0 prefix.

Implemented operations

Grouped by client namespace. Every operation below is covered by tests/mailchimp.test.ts.

Root + Ping

Lists / Audiences (lists.*)

Campaigns (campaigns.*)

Campaign Folders (campaignFolders.*)

Templates (templates.*)

Template Folders (templateFolders.*)

Reports (reports.*, read-only)

E-commerce (ecommerce.*)

File Manager (fileManager.*)

Verified Domains (verifiedDomains.*)

Batch Operations (batches.*)

Search

parlel control / inspection (not part of Mailchimp)

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

FeatureStatusNotes
Root + Ping✅ Supported
Lists/Audiences + members✅ SupportedFull CRUD, MD5 subscriber-hash addressing
Member tags / notes / merge fields✅ Supported
Segments (static + saved)✅ SupportedBatch add/remove members
Interest categories + interests✅ Supported
List webhooks✅ Supported
Campaigns + content + actions✅ Supportedsend/schedule/pause/replicate/test/etc.
Campaign feedback✅ Supported
Campaign + template folders✅ Supported
Templates✅ SupportedClassic templates
Reports + sub-reports✅ Supported (read-only)Sub-reports return empty collections
E-commerce stores/products/customers/orders/carts✅ SupportedCart/order line items via sub-routes
File Manager files + folders✅ Supported
Verified Domains✅ Supported
Batch operations✅ SupportedComplete synchronously
Search members / campaigns✅ Supported
Member event metrics, activity feeds⚠️ StubbedReturn empty collections
List growth/activity/clients/locations⚠️ StubbedReturn empty collections
Automation flows (Customer Journeys)⟳ Roadmap
Classic Automations⟳ Roadmap
Connected Sites⟳ Roadmap
Conversations (deprecated)⟳ Roadmap
Facebook Ads⟳ Roadmap
Landing Pages⟳ Roadmap
Surveys + survey reporting⟳ Roadmap
Account Exports⟳ Roadmap
Authorized Apps⟳ Roadmap
Batch Webhooks⟳ Roadmap
Promo rules / promo codes / product images / variants⟳ Roadmap

Unsupported endpoints return a Mailchimp-shaped 404 Resource Not Found.

Error codes / shapes

Errors follow Mailchimp's RFC 7807 problem+json envelope:

{
  "type": "https://mailchimp.com/developer/marketing/docs/errors/",
  "title": "Invalid Resource",
  "status": 400,
  "detail": "The resource submitted could not be validated. For field-specific details, see the 'errors' array.",
  "instance": "<uuid>",
  "errors": [{ "field": "name", "message": "..." }]
}
StatusTitleWhen
400Invalid ResourceMissing/invalid required fields (includes errors array)
400Member ExistsaddListMember for an email already on the list (use PUT)
400Bad RequestMalformed JSON body, duplicate store/resource id
401API Key InvalidMissing/invalid authorization header
404Resource Not FoundUnknown list/campaign/template/store/etc. or unknown endpoint
405Method Not AllowedUnsupported HTTP method on a known resource
500Internal Server ErrorUnexpected server error

Successful mutations that return no body (member archive/delete, campaign actions, etc.) respond with 204 No Content, matching the real API.

<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

MAILCHIMP_API_KEY=parlel-us1
MAILCHIMP_SERVER_PREFIX=us1
MAILCHIMP_BASE_URL=http://parlel-bridge:4653
MAILCHIMP_API_BASE_URL=http://parlel-bridge:4653/3.0
<!-- parlel:testenv:end -->