How to Test Mailchimp Webhooks
Capture Mailchimp audience events — subscribe, unsubscribe, profile updates, and email changes — without building a server first.
TL;DR: Go to requex.me, copy your URL, then add it in Mailchimp under Audience → Manage Audience → Settings → Webhooks. Mailchimp sends a GET verification first (Requex handles it automatically), then POSTs form-encoded data on every list event.
What Mailchimp Sends
Mailchimp webhooks fire on audience list events. Unlike most modern webhooks that send JSON, Mailchimp sends application/x-www-form-urlencoded data — the same format as an HTML form POST. Your handler needs to parse it with a form-body parser, not JSON.parse().
| Event Type | Trigger | Use Case |
|---|---|---|
subscribe | New subscriber added to audience | Welcome email trigger, CRM sync |
unsubscribe | Subscriber opts out or is cleaned | CRM suppression, compliance logging |
profile | Subscriber updates their profile | Contact record sync |
upemail | Subscriber changes their email address | Update primary key in your database |
campaign | Campaign send starts or completes | Logging, downstream automation |
Important: Mailchimp sends a GET request to your webhook URL when you first save it — this is a reachability check. Requex responds 200 automatically. If your production server doesn't handle GET on the webhook route, Mailchimp will report an error and refuse to save the webhook.
Step 1 — Generate a Requex Endpoint
Open requex.me. Your unique URL is created instantly:
https://requex.me/hook/a1b2c3d4-e5f6-7890-abcd-ef1234567890
Copy this URL and keep the Requex tab open. Each request will appear in the dashboard as it arrives.
Step 2 — Configure Mailchimp Webhook
- Log in to mailchimp.com and select your audience.
- Go to Audience → Manage Audience → Settings, then scroll down to Webhooks.
- Click Create New Webhook.
- Paste your Requex URL into the Callback URL field.
- Check the events you want to receive: subscribes, unsubscribes, profile changes, and email changes are the most useful.
- Choose the sources (Admin, API, Subscriber-initiated) that should trigger the webhook.
- Click Save. Mailchimp will immediately send a GET request to verify the URL — Requex accepts it automatically.
Step 3 — Trigger a Test Event
The simplest way to generate a subscribe event is to use Mailchimp's own signup form. Open your audience's hosted signup form URL (found under Audience → Signup Forms) in a private browser window and submit a test email address. You'll see the subscribe event arrive in Requex within seconds.
To test unsubscribe, go to your audience contacts list, find the test contact, and use the Actions menu to unsubscribe them. Each action fires a separate webhook POST.
Step 4 — Inspect the Payload
In Requex, click the incoming POST request. The raw body will look like URL-encoded form data. Requex also shows it decoded in the Body tab:
// Raw body (URL-encoded)
type=subscribe&fired_at=2026-04-05+12%3A00%3A00&data%5Bid%5D=abc123&data%5Bemail%5D=user%40example.com&data%5Bemail_type%5D=html&data%5Bip_opt%5D=203.0.113.1&data%5Bweb_id%5D=123456&data%5Bmerges%5D%5BEMAIL%5D=user%40example.com&data%5Bmerges%5D%5BFNAME%5D=Jane&data%5Bmerges%5D%5BLNAME%5D=Smith&data%5Blist_id%5D=abc123def
// Parsed equivalent
{
"type": "subscribe",
"fired_at": "2026-04-05 12:00:00",
"data": {
"id": "abc123",
"email": "user@example.com",
"email_type": "html",
"ip_opt": "203.0.113.1",
"merges": {
"EMAIL": "user@example.com",
"FNAME": "Jane",
"LNAME": "Smith"
},
"list_id": "abc123def"
}
}Note that merge fields (first name, last name, custom fields) are nested under data[merges]. The list_id field lets you identify which audience the event came from when multiple audiences post to the same endpoint.
Parsing Form-Encoded Payloads
Because Mailchimp sends application/x-www-form-urlencoded data, you must use a form body parser instead of a JSON parser. Here is how to handle it in Node.js:
// Express — handle Mailchimp form-encoded webhooks
const express = require('express');
const app = express();
// IMPORTANT: use urlencoded parser, not json()
app.use(express.urlencoded({ extended: true }));
// Handle both GET (verification) and POST (events)
app.get('/webhooks/mailchimp', (req, res) => {
res.sendStatus(200); // Mailchimp reachability check
});
app.post('/webhooks/mailchimp', (req, res) => {
const { type, fired_at, data } = req.body;
switch (type) {
case 'subscribe':
console.log('New subscriber:', data.email);
// Sync to your CRM here
break;
case 'unsubscribe':
console.log('Unsubscribed:', data.email, 'reason:', data.reason);
break;
case 'upemail':
console.log('Email changed from', data.old_email, 'to', data.new_email);
break;
case 'profile':
console.log('Profile updated:', data.email);
break;
}
res.sendStatus(200);
});Common Issues
| Problem | Cause | Fix |
|---|---|---|
| Webhook fails to save in Mailchimp | Your server returns non-200 on the GET verification | Add a GET route at the same path that returns 200 OK |
| Body is empty or garbled | Using JSON body parser instead of urlencoded | Switch to express.urlencoded({ extended: true }) |
| No events arriving after save | Event sources not checked (API, Admin, Subscriber) | Edit the webhook and enable all three source checkboxes |
Test Mailchimp Webhooks Free
Capture real Mailchimp audience events and inspect every field. No signup required.
Open Requex →Related guides
Start Testing Webhooks Now
Generate your unique URL and test webhooks instantly. Free, no signup.
Open Webhook Tester →