Skip to main content
RapidDev - Software Development Agency
bolt-ai-integrationsBolt Chat + API Route

How to Integrate Bolt.new with Campaign Monitor

Campaign Monitor integrates with Bolt.new through a Next.js API route using HTTP Basic authentication with your API key. Get the key from Account Settings → API keys, store it in .env, and call Campaign Monitor's REST API to manage subscriber lists, add subscribers, create email campaigns, and fetch analytics. Campaign Monitor focuses on branded email design and has a generous free-to-test API with no minimum plan requirement.

What you'll learn

  • How to get a Campaign Monitor API key and configure HTTP Basic auth correctly
  • How to add and manage subscribers in Campaign Monitor lists from Bolt.new API routes
  • How to create email campaigns and import HTML templates via the Campaign Monitor API
  • How to fetch campaign analytics (open rates, click rates, bounces) and display them in a React dashboard
  • How to build a subscriber management dashboard for Campaign Monitor lists in a Bolt.new app
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate17 min read20 minutesMarketingApril 2026RapidDev Engineering Team
TL;DR

Campaign Monitor integrates with Bolt.new through a Next.js API route using HTTP Basic authentication with your API key. Get the key from Account Settings → API keys, store it in .env, and call Campaign Monitor's REST API to manage subscriber lists, add subscribers, create email campaigns, and fetch analytics. Campaign Monitor focuses on branded email design and has a generous free-to-test API with no minimum plan requirement.

Campaign Monitor Email Marketing Integration for Bolt.new Apps

Campaign Monitor has built its reputation on design quality — the platform is used by agencies and design-conscious brands that prioritize beautiful, on-brand email templates over raw automation complexity. While Mailchimp has more automation features and a better free tier, Campaign Monitor excels at producing polished, responsive email campaigns that match a brand's visual identity precisely. The platform's template builder, which supports both drag-and-drop and custom HTML/CSS imports, gives creative teams more control over email design than most competitors.

For Bolt.new developers, Campaign Monitor integration typically comes in two forms. The first is subscriber capture — adding subscribers from a Bolt-built website or landing page directly to a Campaign Monitor list, triggering welcome sequences and nurture campaigns. The second is building internal tools: a campaign analytics dashboard for teams reviewing email performance, or a subscriber management interface for content teams who manage lists without needing full Campaign Monitor account access.

Campaign Monitor's API uses HTTP Basic auth with the API key as the username — an authentication pattern that requires no OAuth flow, no redirect URIs, and no token expiration management. This makes it one of the simpler email marketing APIs to integrate. The API key gives full access to all clients and campaigns associated with your Campaign Monitor account, so keeping it server-side (never prefixed with NEXT_PUBLIC_) is essential. The API covers all core functionality: subscriber lists, subscriber management (add, update, delete, import), campaigns (create, send, schedule), templates, and detailed analytics reports.

Integration method

Bolt Chat + API Route

Campaign Monitor uses HTTP Basic authentication with the API key as the username and any string (commonly 'x') as the password. The API key is Base64-encoded and sent in the Authorization header. All API requests go through Next.js server-side API routes to keep the key out of the browser bundle. Campaign Monitor's REST API provides subscriber management, campaign creation, and analytics through standard HTTP endpoints.

Prerequisites

  • A Campaign Monitor account (campaignmonitor.com) — a free account allows API testing; paid plans required for sending campaigns to real subscribers
  • Your Campaign Monitor API key from Account Settings (top-right avatar) → API Keys — you may need to generate one if none exists
  • Your Campaign Monitor Client ID (found in Account Settings → Clients, or in the URL when viewing a client) — required for campaign management endpoints
  • A Campaign Monitor subscriber list ID — found in the list settings URL when viewing a list in Campaign Monitor
  • A Bolt.new project using Next.js for API routes that keep the API key server-side

Step-by-step guide

1

Get your Campaign Monitor API key and configure authentication

Campaign Monitor uses HTTP Basic authentication with the API key as the username and any non-empty string as the password — the convention is to use 'x' as the password, but Campaign Monitor accepts any value. The authentication is encoded as Base64 of 'API_KEY:x' and sent in the Authorization header. To get your API key, log into Campaign Monitor and click your account name or avatar in the top-right corner. Select 'Account Settings' from the dropdown. Navigate to the 'API keys' section. If no API key exists, click 'Generate API key.' Copy the key — it is a 40-character hexadecimal string. In Node.js, construct the auth header as: Buffer.from(`${apiKey}:x`).toString('base64'). The full Authorization header is: Authorization: Basic {base64string}. This pattern is simpler than Insightly's API (which uses an empty password) because Campaign Monitor explicitly accepts 'x' as the placeholder password. You also need your Campaign Monitor Client ID for endpoints that manage campaigns. Find it in Account Settings → Clients, or look at the URL when you are viewing a client in the Campaign Monitor UI — the numeric-looking ID in the URL path is the client ID. This is different from your API key and specific to the client (brand) you are managing. For subscriber list management, each list has its own ID. Find it in Campaign Monitor by navigating to a list and looking at the URL, or via the API: GET /clients/{clientId}/lists.json returns all lists with their IDs and names. Store the API key as CAMPAIGN_MONITOR_API_KEY in .env (server-side, no NEXT_PUBLIC_ prefix). Store the client ID as CAMPAIGN_MONITOR_CLIENT_ID and your primary list ID as CAMPAIGN_MONITOR_LIST_ID. All three are needed for the common operations covered in this guide.

Bolt.new Prompt

Add Campaign Monitor API credentials to .env. Create the file with: CAMPAIGN_MONITOR_API_KEY=your_api_key_here (server-side only, never NEXT_PUBLIC_), CAMPAIGN_MONITOR_CLIENT_ID=your_client_id_here, CAMPAIGN_MONITOR_LIST_ID=your_list_id_here. Add comments explaining where to find each value in Campaign Monitor's settings.

Paste this in Bolt.new chat

.env
1# .env
2# Campaign Monitor API key server-side only, never NEXT_PUBLIC_
3# Get from Campaign Monitor: account avatar Account Settings API keys
4CAMPAIGN_MONITOR_API_KEY=your_40_char_hex_key_here
5
6# Campaign Monitor Client ID numeric-looking string for the brand/client
7# Find in Account Settings Clients, or in the URL when viewing a client
8CAMPAIGN_MONITOR_CLIENT_ID=your_client_id_here
9
10# Subscriber list ID for signup forms
11# Find in Campaign Monitor Lists click a list copy ID from URL
12CAMPAIGN_MONITOR_LIST_ID=your_list_id_here

Pro tip: Campaign Monitor uses 'x' as the conventional placeholder password in Basic auth, but any non-empty string works. The actual authentication is based solely on the API key (username). Using Buffer.from(`${apiKey}:x`).toString('base64') is the standard pattern you will see in Campaign Monitor's official code examples.

Expected result: The Campaign Monitor API key is stored in .env. You can test it by making a GET request to https://api.createsend.com/api/v3.3/clients/{YOUR_CLIENT_ID}/lists.json with the Basic auth header — it should return your subscriber lists as JSON.

2

Build the Campaign Monitor API service and subscriber routes

Create the Campaign Monitor API service module and Next.js API routes for subscriber management. Campaign Monitor's API base URL is https://api.createsend.com/api/v3.3/ for the current version. All endpoints follow RESTful conventions with JSON responses. The primary subscriber endpoints are: POST /subscribers/{listId}.json (add or re-subscribe a subscriber — specify Resubscribe: true to re-add previously unsubscribed contacts), GET /subscribers/{listId}.json?email={email} (find a specific subscriber by email), PUT /subscribers/{listId}.json (update a subscriber's details), POST /subscribers/{listId}/unsubscribe.json (unsubscribe a contact), and GET /lists/{listId}/active.json (paginated list of active subscribers). When adding a subscriber, the required fields are EmailAddress and Name. Optional fields include Resubscribe (boolean — whether to re-add unsubscribed contacts), RestartSubscriptionBasedAutoresponders (boolean — whether to trigger welcome automation), and CustomFields (array of {Key, Value} objects for custom subscriber data you have defined in the list). Campaign Monitor returns HTTP 200 for successful subscriber operations regardless of whether the subscriber was created or updated — there is no 201 Created vs 200 OK distinction. A 400 response indicates validation errors with a descriptive error Code and Message in the response body. Common 400 codes: 1 (invalid email address), 203 (list is at capacity), 210 (email in suppression list). Build the service module with typed helper functions and verify the subscriber endpoint in Bolt's preview. Outbound calls to api.createsend.com work in the WebContainer since they use standard HTTPS.

Bolt.new Prompt

Create a Campaign Monitor API integration. (1) Create lib/campaign-monitor.ts with a cmFetch(endpoint, options) utility using CAMPAIGN_MONITOR_API_KEY Basic auth (base64 of 'key:x') against https://api.createsend.com/api/v3.3. Export: addSubscriber(listId, email, name, customFields?, resubscribe?) that POSTs to /subscribers/{listId}.json; getLists(clientId) that GETs /clients/{clientId}/lists.json; getActiveSubscribers(listId, page?) that GETs /lists/{listId}/active.json; and getCampaigns(clientId) that GETs /clients/{clientId}/campaigns.json. (2) Create app/api/campaign-monitor/subscribe/route.ts with POST accepting { email, name, customFields } that calls addSubscriber with CAMPAIGN_MONITOR_LIST_ID. Return the subscriber email on success.

Paste this in Bolt.new chat

lib/campaign-monitor.ts
1// lib/campaign-monitor.ts
2const CM_BASE = 'https://api.createsend.com/api/v3.3';
3
4function getCMAuth(): string {
5 const key = process.env.CAMPAIGN_MONITOR_API_KEY;
6 if (!key) throw new Error('CAMPAIGN_MONITOR_API_KEY not configured');
7 // Campaign Monitor Basic auth: Base64 of 'api_key:x'
8 return Buffer.from(`${key}:x`).toString('base64');
9}
10
11async function cmFetch<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
12 const res = await fetch(`${CM_BASE}${endpoint}`, {
13 ...options,
14 headers: {
15 Authorization: `Basic ${getCMAuth()}`,
16 'Content-Type': 'application/json',
17 ...options.headers,
18 },
19 });
20
21 if (!res.ok) {
22 const body = await res.json().catch(() => ({ Message: res.statusText }));
23 throw Object.assign(new Error(body.Message ?? 'Campaign Monitor API error'), {
24 status: res.status,
25 code: body.Code,
26 body,
27 });
28 }
29
30 return res.json();
31}
32
33export interface CMCustomField {
34 Key: string;
35 Value: string;
36}
37
38export async function addSubscriber(
39 listId: string,
40 email: string,
41 name: string,
42 customFields: CMCustomField[] = [],
43 resubscribe = true
44) {
45 return cmFetch<string>(`/subscribers/${listId}.json`, {
46 method: 'POST',
47 body: JSON.stringify({
48 EmailAddress: email,
49 Name: name,
50 CustomFields: customFields,
51 Resubscribe: resubscribe,
52 RestartSubscriptionBasedAutoresponders: resubscribe,
53 }),
54 });
55}
56
57export async function getLists(clientId?: string) {
58 const id = clientId ?? process.env.CAMPAIGN_MONITOR_CLIENT_ID;
59 if (!id) throw new Error('CAMPAIGN_MONITOR_CLIENT_ID not configured');
60 return cmFetch<Array<{ ListID: string; Name: string }>>(`/clients/${id}/lists.json`);
61}
62
63export async function getActiveSubscribers(listId: string, page = 1, pageSize = 100) {
64 return cmFetch(`/lists/${listId}/active.json?page=${page}&pagesize=${pageSize}`);
65}
66
67export async function getCampaigns(clientId?: string) {
68 const id = clientId ?? process.env.CAMPAIGN_MONITOR_CLIENT_ID;
69 if (!id) throw new Error('CAMPAIGN_MONITOR_CLIENT_ID not configured');
70 return cmFetch<Array<{ CampaignID: string; Name: string; Subject: string; SentDate: string }>(
71 `/clients/${id}/campaigns.json`
72 );
73}

Pro tip: Campaign Monitor's API field names use PascalCase (EmailAddress, not email or emailAddress). The subscriber endpoint returns the subscriber's email address (not an ID) as the response body on success — this is different from most REST APIs that return a created resource ID.

Expected result: lib/campaign-monitor.ts provides authenticated access to Campaign Monitor's API. The /api/campaign-monitor/subscribe route adds subscribers to the configured list. Submitting the signup form in Bolt's preview adds a real subscriber to your Campaign Monitor list.

3

Build the campaign analytics dashboard

A campaign analytics dashboard that surfaces Campaign Monitor email performance metrics for teams reviewing results without needing direct Campaign Monitor access. Campaign Monitor provides detailed analytics through its reporting API endpoints. Fetch campaigns via GET /clients/{clientId}/campaigns.json, which returns sent campaigns with basic metadata: CampaignID, Name, Subject, SentDate, TotalRecipients, and a WebVersionURL. For each campaign, fetch detailed stats via GET /campaigns/{campaignId}/summary.json, which returns comprehensive analytics: Bounces, Clicks, Opens, Recipients, SpamComplaints, TotalOpened, UniqueOpened, Unsubscribes, WebVersionURL, and WorldviewURL. The most important metrics for the dashboard are: unique open rate (UniqueOpened / Recipients), click-to-open rate (Clicks / UniqueOpened), and unsubscribe rate (Unsubscribes / Recipients). Campaign Monitor returns absolute numbers rather than percentages — calculate rates in your API route or React component. For the Recharts visualization, a horizontal bar chart comparing open rates across recent campaigns works well — horizontal bars accommodate longer campaign names better than vertical bars. Color-code bars above 25% as green (above average for email), 15-24% as yellow (average), and below 15% as red (below average). These benchmarks vary by industry but provide useful relative context. For click tracking data, Campaign Monitor also provides link performance through GET /campaigns/{campaignId}/clicks.json, which shows each link clicked and the unique/total click counts. This is useful for identifying which content resonates with subscribers and can be displayed in a detail view for individual campaigns.

Bolt.new Prompt

Build a Campaign Monitor analytics dashboard at app/dashboard/campaigns/page.tsx. (1) Create /api/campaign-monitor/campaigns that calls getCampaigns() from lib/campaign-monitor.ts. (2) Create /api/campaign-monitor/campaigns/[id]/summary that GETs https://api.createsend.com/api/v3.3/campaigns/{id}/summary.json with CM Basic auth. Calculate and return uniqueOpenRate (UniqueOpened/Recipients), clickRate (Clicks/Recipients), and bounceRate (Bounces/Recipients) as percentages. (3) In React, display campaigns in a list with columns: Name, Date Sent, Recipients, Unique Opens %, Clicks %. Add a Recharts HorizontalBarChart comparing open rates for the last 10 campaigns with color coding (green >25%, yellow 15-25%, red <15%). Clicking a campaign shows a detail panel.

Paste this in Bolt.new chat

app/api/campaign-monitor/campaigns/[id]/summary/route.ts
1// app/api/campaign-monitor/campaigns/[id]/summary/route.ts
2import { NextResponse } from 'next/server';
3
4export async function GET(
5 _request: Request,
6 { params }: { params: { id: string } }
7) {
8 const apiKey = process.env.CAMPAIGN_MONITOR_API_KEY;
9 if (!apiKey) {
10 return NextResponse.json({ error: 'CAMPAIGN_MONITOR_API_KEY not configured' }, { status: 500 });
11 }
12
13 const auth = Buffer.from(`${apiKey}:x`).toString('base64');
14 const res = await fetch(
15 `https://api.createsend.com/api/v3.3/campaigns/${params.id}/summary.json`,
16 { headers: { Authorization: `Basic ${auth}` } }
17 );
18
19 if (!res.ok) {
20 return NextResponse.json({ error: 'Failed to fetch campaign summary' }, { status: res.status });
21 }
22
23 const data = await res.json();
24 const recipients = data.Recipients ?? 1; // avoid division by zero
25
26 return NextResponse.json({
27 campaignId: params.id,
28 recipients: data.Recipients,
29 uniqueOpened: data.UniqueOpened,
30 totalOpened: data.TotalOpened,
31 clicks: data.Clicks,
32 bounces: data.Bounces,
33 unsubscribes: data.Unsubscribes,
34 spamComplaints: data.SpamComplaints,
35 // Calculated rates as percentages
36 uniqueOpenRate: ((data.UniqueOpened / recipients) * 100).toFixed(1),
37 clickRate: ((data.Clicks / recipients) * 100).toFixed(1),
38 bounceRate: ((data.Bounces / recipients) * 100).toFixed(1),
39 clickToOpenRate: data.UniqueOpened > 0
40 ? ((data.Clicks / data.UniqueOpened) * 100).toFixed(1)
41 : '0.0',
42 });
43}

Pro tip: Campaign Monitor returns absolute numbers (UniqueOpened: 1250) not percentages. Calculate rates in your API route or React component. For email benchmarks: open rates above 25% are excellent, 15-25% is average, below 15% needs attention — though rates vary significantly by industry and list quality.

Expected result: The campaign analytics dashboard lists recent Campaign Monitor campaigns with open and click rates. The horizontal bar chart provides a visual comparison across campaigns with color-coded performance indicators. Clicking a campaign shows the detail panel with all metrics.

4

Add subscriber list management and segmentation

Complete the integration with subscriber list management features: viewing active subscribers, searching for specific subscribers, updating custom field data, and managing unsubscribes. This is useful for content teams who manage subscriber lists without needing full Campaign Monitor account access. Campaign Monitor's subscriber list endpoints return paginated results. The active subscribers endpoint (GET /lists/{listId}/active.json) supports pagination with page and pagesize parameters, returning results with a TotalNumberOfRecords field and a Results array. The maximum page size is 1000 subscribers per request. Subscriber records include EmailAddress, Name, Date (subscription date), State (Active, Unsubscribed, Bounced, Deleted), and CustomFields (an array of {Key, Value} objects). Custom fields you define in the Campaign Monitor list settings appear in every subscriber record. For unsubscribing a contact: POST /subscribers/{listId}/unsubscribe.json with { 'EmailAddress': email }. For updating subscriber details: PUT /subscribers/{listId}.json with the same payload format as add subscriber (the API uses the email to find the existing record and update it). Building a subscriber search UI requires fetching by email — Campaign Monitor does not have a global search endpoint, so you search within a specific list using GET /subscribers/{listId}.json?email={email}. For multi-list search, make parallel requests to each list and aggregate results.

Bolt.new Prompt

Create a Campaign Monitor subscriber management interface. (1) /api/campaign-monitor/subscribers route with GET accepting listId and optional email query params. If email is provided, call GET /subscribers/{listId}.json?email={email}. Otherwise, call getActiveSubscribers(listId). (2) /api/campaign-monitor/subscribers/unsubscribe route with POST accepting { email, listId } that POSTs to /subscribers/{listId}/unsubscribe.json. (3) Build a React management page: dropdown to select a list, email search input, subscriber table with columns (Email, Name, Date Subscribed, Status), and 'Unsubscribe' action button per row. Show subscriber count and list health (active/bounced/unsubscribed breakdown). Use Tailwind CSS.

Paste this in Bolt.new chat

app/api/campaign-monitor/subscribers/route.ts
1// app/api/campaign-monitor/subscribers/route.ts
2import { NextResponse } from 'next/server';
3import { getActiveSubscribers } from '@/lib/campaign-monitor';
4
5export async function GET(request: Request) {
6 const { searchParams } = new URL(request.url);
7 const listId = searchParams.get('listId') ?? process.env.CAMPAIGN_MONITOR_LIST_ID;
8 const email = searchParams.get('email');
9 const page = parseInt(searchParams.get('page') ?? '1');
10
11 if (!listId) {
12 return NextResponse.json({ error: 'listId required' }, { status: 400 });
13 }
14
15 const apiKey = process.env.CAMPAIGN_MONITOR_API_KEY!;
16 const auth = Buffer.from(`${apiKey}:x`).toString('base64');
17
18 try {
19 if (email) {
20 // Search for specific subscriber by email
21 const res = await fetch(
22 `https://api.createsend.com/api/v3.3/subscribers/${listId}.json?email=${encodeURIComponent(email)}`,
23 { headers: { Authorization: `Basic ${auth}` } }
24 );
25 if (!res.ok) return NextResponse.json({ subscriber: null });
26 return NextResponse.json({ subscriber: await res.json() });
27 }
28
29 // Get paginated active subscribers
30 const data = await getActiveSubscribers(listId, page);
31 return NextResponse.json(data);
32 } catch (error) {
33 const message = error instanceof Error ? error.message : 'Unknown error';
34 return NextResponse.json({ error: message }, { status: 500 });
35 }
36}

Pro tip: When searching for a subscriber by email, Campaign Monitor returns the subscriber's current status (Active, Unsubscribed, Bounced) along with their subscription history. Use this to show whether a contact is currently receiving emails and when they last changed status.

Expected result: The subscriber management interface shows a paginated list of active subscribers with search capability. The unsubscribe action removes contacts from the list and the UI updates optimistically. List health metrics show the breakdown of active, bounced, and unsubscribed contacts.

Common use cases

Subscriber Capture from Bolt Landing Page

A newsletter or lead magnet signup form on a Bolt-built landing page that adds new subscribers to a Campaign Monitor list when submitted. The subscriber receives an immediate branded welcome email configured in Campaign Monitor, while the marketing team sees the new subscriber in their Campaign Monitor dashboard.

Bolt.new Prompt

Add a newsletter signup form to this landing page that subscribes users to Campaign Monitor. Create a form component with name and email fields. On submit, POST to /api/campaign-monitor/subscribe which calls https://api.createsend.com/api/v3.3/subscribers/{CAMPAIGN_MONITOR_LIST_ID}.json using Basic auth with CAMPAIGN_MONITOR_API_KEY. Set the subscriber's Name and EmailAddress fields. Use Resubscribe: true to re-add unsubscribed contacts. Show a success message on submission. Handle duplicate emails gracefully (Campaign Monitor returns 200 for existing subscribers when Resubscribe is true). Use TypeScript and Tailwind CSS.

Copy this prompt to try it in Bolt.new

Campaign Analytics Dashboard

An internal campaign performance dashboard showing Campaign Monitor email analytics — opens, clicks, bounces, and unsubscribes for recent campaigns. Design leads and account managers can review email performance in a custom interface alongside other project metrics without needing individual Campaign Monitor logins.

Bolt.new Prompt

Build a Campaign Monitor campaign analytics dashboard. Create /api/campaign-monitor/campaigns that GETs https://api.createsend.com/api/v3.3/clients/{CAMPAIGN_MONITOR_CLIENT_ID}/campaigns.json using CAMPAIGN_MONITOR_API_KEY Basic auth. Create /api/campaign-monitor/campaigns/[id]/summary that GETs /campaigns/{campaignId}/summary.json for open rate, click rate, bounces, unsubscribes. In React, display a list of recent campaigns with name, sent date, recipient count, open rate, and click rate. Add a Recharts BarChart comparing open vs click rates for the last 10 campaigns. Clicking a campaign shows a detail panel with the full summary stats.

Copy this prompt to try it in Bolt.new

Subscriber List Management Interface

A subscriber management tool that allows content team members to view, search, and segment subscribers across Campaign Monitor lists without needing full account access. Team members can check if an email is subscribed, remove specific subscribers, and view list growth metrics — all from a custom Bolt interface.

Bolt.new Prompt

Create a Campaign Monitor subscriber management interface. Build /api/campaign-monitor/subscribers that accepts a GET with optional email query param and searches for the subscriber across all lists. Build /api/campaign-monitor/subscribers/[listId] that returns active subscribers for that list with pagination. Create a React interface with a search input to look up subscribers by email — call GET /subscribers/{listId}.json?email={email} for each list using CAMPAIGN_MONITOR_API_KEY. Show subscriber status, date subscribed, and custom fields. Add an 'Unsubscribe' button that POSTs to the unsubscribe endpoint. Display list growth chart using Recharts.

Copy this prompt to try it in Bolt.new

Troubleshooting

Campaign Monitor API returns 401 Unauthorized on all requests

Cause: The Basic auth header is incorrectly formatted. Campaign Monitor requires Base64 encoding of 'API_KEY:x' (key followed by colon and the letter x). Using just the key, or encoding 'API_KEY:' with an empty password, may also cause auth failures.

Solution: Verify the auth construction: Buffer.from(`${apiKey}:x`).toString('base64'). The full Authorization header is 'Basic ' followed by the Base64 string. Confirm the API key in .env is exactly 40 characters and has no leading or trailing whitespace. Test by pasting your Base64-encoded credentials into a Base64 decoder to verify the 'key:x' format.

typescript
1// Correct Campaign Monitor Basic auth
2const apiKey = process.env.CAMPAIGN_MONITOR_API_KEY;
3// CORRECT: encode 'apikey:x' (x is placeholder password)
4const auth = Buffer.from(`${apiKey}:x`).toString('base64');
5const headers = { Authorization: `Basic ${auth}` };

POST to /subscribers returns 400 with Code 1 (Invalid email address)

Cause: The email address in the EmailAddress field failed Campaign Monitor's email validation. This can happen with test email addresses, email addresses with unusual formatting, or if the field name is incorrectly cased.

Solution: Ensure the JSON payload uses PascalCase field names: { EmailAddress: email, Name: name }. Lowercase 'emailAddress' or 'email' will be silently ignored and Campaign Monitor will report a missing required field. Validate the email format client-side before submission to catch obvious formatting errors.

typescript
1// Correct Campaign Monitor subscriber payload (PascalCase fields)
2const payload = {
3 EmailAddress: email, // NOT: emailAddress or email
4 Name: name, // NOT: name (lowercase works here but PascalCase is safer)
5 Resubscribe: true,
6 RestartSubscriptionBasedAutoresponders: true,
7 CustomFields: [],
8};

Campaign Monitor subscriber count shows in dashboard but analytics returns empty campaigns array

Cause: The CAMPAIGN_MONITOR_CLIENT_ID is incorrect or belongs to a different account than the list ID. Campaign Monitor's campaign endpoints are scoped to clients (brands), not accounts.

Solution: Verify your Client ID by calling GET /clients/{clientId}/details.json with your API key — if it returns client details, the ID is correct. Find your Client ID in Campaign Monitor's URL when viewing a client, or use GET /clients.json (requires account-level API key) to list all clients. The campaign analytics endpoints require the Client ID, not the list ID.

Best practices

  • Store the Campaign Monitor API key in server-side .env with no NEXT_PUBLIC_ prefix — it provides full access to all subscriber lists and campaign management across your account
  • Use Resubscribe: true on subscriber addition to re-add unsubscribed contacts who opt in again — without this, re-adding an unsubscribed email silently fails and the contact remains unsubscribed
  • Always use PascalCase for Campaign Monitor API field names (EmailAddress, Name, CustomFields) — lowercase alternatives may be accepted in some cases but PascalCase is the documented standard and more reliable
  • Fetch campaign summaries for the campaigns list view lazily or cache them — fetching detailed stats for every campaign on page load creates N+1 API requests for accounts with many campaigns
  • Use Campaign Monitor's CustomFields feature to capture additional subscriber data (source, lead magnet, UTM parameters) by adding them to the list definition in Campaign Monitor before sending them via API
  • Implement the Resubscribe and RestartSubscriptionBasedAutoresponders flags consistently — setting them to true ensures returning subscribers receive welcome emails and re-enter automation sequences
  • Test your subscriber signup flow with real email addresses on the deployed Bolt app — the Bolt WebContainer preview works for outbound API calls to Campaign Monitor, but email delivery testing requires real subscriber data

Alternatives

Frequently asked questions

Does Campaign Monitor work with Bolt.new?

Yes. Campaign Monitor's REST API uses standard HTTPS requests that work in Bolt's WebContainer via a Next.js API route. Campaign Monitor uses HTTP Basic auth with an API key — no OAuth flow or redirect URI is required. You can test the complete integration (subscribing contacts, fetching campaigns) directly in the Bolt preview without deploying first.

How do I connect Bolt.new to Campaign Monitor?

Get your API key from Campaign Monitor Account Settings → API keys. Store it in .env as CAMPAIGN_MONITOR_API_KEY. Create a Next.js API route that constructs Basic auth by encoding 'API_KEY:x' as Base64 and adds it as an Authorization header to requests to https://api.createsend.com/api/v3.3. React components call your API routes — never Campaign Monitor's API directly — to keep the key server-side.

What is the Campaign Monitor API key format and where do I find it?

The Campaign Monitor API key is a 40-character hexadecimal string. Find it in Campaign Monitor by clicking your account name or avatar in the top-right corner, selecting 'Account Settings,' and navigating to the 'API keys' section. If no key exists, click 'Generate API key.' The key provides full API access to all subscriber lists and campaigns in your account.

How do I add subscribers to Campaign Monitor from a Bolt.new form?

Create a Next.js API route that POSTs to https://api.createsend.com/api/v3.3/subscribers/{listId}.json with Basic auth. The request body must use PascalCase fields: { EmailAddress: email, Name: name, Resubscribe: true }. The Resubscribe flag ensures previously unsubscribed contacts can be re-added if they opt in again. React form components call your API route — never Campaign Monitor directly.

Can I use Campaign Monitor in Bolt's WebContainer preview without deploying?

Yes. Campaign Monitor uses API key authentication with no OAuth redirect URI requirement, so the full integration works in Bolt's WebContainer preview. Outbound HTTPS calls to api.createsend.com work normally. You can test subscriber addition, campaign fetching, and analytics retrieval in development before deploying. Deploy when you are ready to share with users or need a stable public URL.

How do I fetch campaign analytics from Campaign Monitor in Bolt.new?

Use two API calls: GET /clients/{clientId}/campaigns.json to list campaigns, and GET /campaigns/{campaignId}/summary.json for detailed stats per campaign. The summary returns absolute numbers (UniqueOpened, Clicks, Bounces) — calculate rates by dividing by Recipients. Fetch summaries lazily (only when a campaign is selected) rather than for all campaigns at once to avoid N+1 API calls.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.