Skip to main content
A campaign turns a list into an outbound sequence. The API mirrors how campaigns work in the app: you create a draft, Fuse initializes it asynchronously, you review and edit the sequence steps, and nothing sends until you explicitly approve it. That last part is deliberate — a campaign contacts real people, so the API never activates one as a side effect of creating it. The full flow is four calls:
  1. POST /business/campaigns — create the draft.
  2. GET /business/campaigns/{campaignId} — poll until initialization completes.
  3. GET /business/campaigns/{campaignId}/steps — review (and optionally PATCH) the sequence.
  4. POST /business/campaigns/{campaignId}/approve — activate it.
Campaign endpoints require a key with the campaigns scope. See scopes.
Sending accounts (email and LinkedIn) are connected in the Fuse app, not via the API. Connect at least one before you approve — approval fails with CAMPAIGN_NOT_READY if no sending account is available.

Manual vs. AI-generated

Every campaign is one of two types, set by campaignType at creation:
  • manual (the default) — you write the subject and body of every step yourself.
  • ai-generated — Fuse writes the copy during initialization, guided by your prompt, your team’s knowledge hub and your writing style.
The type decides which request fields are valid and which step fields you edit later: manual steps have a subject and body you own; AI steps are driven by a topic. AI-only fields on a manual campaign are rejected, not ignored — the request fails so you find out immediately rather than wondering why your prompt had no effect.
1

Create the draft

Provide a campaignName, exactly one of listId or listIds (up to 10 lists), and a channels array with one entry per sequence step, in order. channels defaults to a single email step.
A 201 means the draft was accepted, not that it is ready — initialization runs in the background, which is what the next step polls for.Core fields:Scheduling (all optional):Exclusions (all optional):Enrollment and personalization (all optional):AI-only fields — valid only when campaignType is "ai-generated"; a manual campaign rejects them:websiteUrls and additionalInfo are no longer accepted and answer 422 VALIDATION_FAILED. Put product context in your team’s knowledge hub instead.The endpoint accepts a few additional toggles (unsubscribe link, open-rate tracking, and others) — see the API reference for the full request schema.
All errors use the standard error envelope.
Reachability is computed asynchronously after contacts are added or enriched. If you create a campaign immediately after populating a list, you may get LIST_INCOMPATIBLE_WITH_CHANNELS even though the contacts have emails — the list’s stats simply have not caught up. Wait a little and retry; a backoff of a minute or two between attempts is plenty.
2

Poll until initialization completes

Initialization is asynchronous — for AI campaigns it includes generating the copy for every step, which takes time. Poll the campaign until initializationStatus is "completed":
status and initializationStatus answer different questions: status is the campaign’s lifecycle state (it stays pre-active until you approve), while initializationStatus tells you whether the draft is ready to review. When AI generation fails, initializationError carries readable status text explaining what went wrong.
3

Review the sequence

Once initialized, fetch the steps and read what will actually go out:
sequenceNumber orders the steps, starting at 0, and daysBetween is the wait, in days, after the previous step. If anything needs changing, edit it now — see Editing steps below. Approval is the point of no return, so this is the moment to check the copy, the merge tokens, and (for AI campaigns) that every step has a topic.
4

Approve

Approval is the explicit go signal. It validates that the campaign is complete and then activates it:
The 202 means activation was accepted; sending follows your schedule (campaignStartDate, emailDays, timezone) between 09:00 and 17:00 local time. If approval fails instead, see Troubleshooting approval.

Editing steps

PATCH /business/campaigns/{campaignId}/steps/{stepId} edits one step and returns { "stepId": "..." }. Which fields you set depends on the campaign type: on manual steps you write the subject and body; on AI steps you set the topic and let generation handle the copy. Either way you can adjust daysBetween (0–365). Send subject and body together. The pair replaces the step’s whole template, so sending only one answers 422 VALIDATION_FAILED.
Limits: subject up to 500 characters, body up to 50,000, topic up to 1,000. On a linkedin_connection step, body is the note attached to the connection request, and LinkedIn caps it at 200 characters — a longer body answers 422 CONNECTION_NOTE_TOO_LONG. Leave it empty to send the request without a note. The same note is what the app shows for the step and what POST .../duplicate carries into the copy.

Merge tokens

Step content supports three kinds of tokens:
  • Built-in tokens — {Contact First Name}, {Contact Last Name}, {Contact Full Name}, {Contact Company}, {Contact Job Title} and {Contact Industry} fill from the contact’s own fields, and {Sender First Name}, {Sender Last Name}, {Sender Full Name}, {Sender Job Title} and {Sender Signature} from the sending account. {CTA Link} renders the campaign’s ctaLink.
  • Column tokens — {Column: <name>}, filled from the list’s custom columns. {Column: Pain point} renders the value of the “Pain point” column for that contact.
  • AI tokens — {{<instruction>}} has the AI write that part of the message for each contact from their data, for example {{one line about their company's latest launch}}. {{<instruction> :: <original text>}} rewrites the original text and keeps it as the fallback.
Tokens use single braces and exact names. A near miss such as {firstName} is not substituted and reaches the prospect as typed, so preview a step before approving. A column token renders whatever the contact’s cell holds when their step is scheduled, so fill a column for everyone before the campaign reaches them:
  • A blank cell renders as nothing. An empty custom column, or a smart column that failed or found nothing for that contact, leaves a gap where the token was, and the message still sends. Preview a step to see it the way a prospect will.
  • A smart column that is still running stops the contact. If a contact’s smart-column cell is still being researched when their step comes due, that step is not scheduled and the contact stops. It is not retried automatically when the value lands, so let a smart column finish before you approve, and before you add rows to a dynamic campaign’s lists. Personalize every email with AI research shows the safe order.
  • Values are snapshotted when an email is queued. Rendering happens at schedule time and the result is frozen onto the queued email; overwriting a column value afterwards does not rewrite emails already queued. Write values before the step schedules if they must be current.
  • Multiple lists: when a campaign draws from several lists and a contact’s column exists on more than one, the first list (in the campaign’s list order) with a non-empty value wins.
The topic gotcha. An AI campaign created from a templateId whose template was captured from a manual campaign inherits each step’s subject and body — but no topic. Approval requires a topic on every AI-generated step, so this combination fails with 422 CAMPAIGN_NOT_READY until you PATCH a topic onto each step.

Troubleshooting approval

Approval failures come back in the standard error envelope:
CAMPAIGN_NOT_READY is the one you fix and retry: add the missing content via step edits, set a ctaLink with PATCH /business/campaigns/{campaignId}, or connect a sending account in the app, then call approve again. CAMPAIGN_NOT_APPROVABLE on an active campaign means there is nothing to do.

Preview a step before anyone sees it

POST /business/campaigns/{campaignId}/steps/{stepId}/generate renders a step for a sample lead — variables filled, AI copy generated — without saving or sending anything.
It is the cheapest way to check that a template reads well and that every variable resolves before the campaign goes live. To rebuild the AI topic plan across every AI step at once, POST /business/campaigns/{campaignId}/steps/regenerate-topics returns how many it touched:

Know which variables you can use

GET /business/campaigns/{campaignId}/variables lists the column tokens this campaign’s steps can reference, taken from the custom and smart columns on its source lists. Built-in tokens such as {Contact First Name} are always available and are not listed.
Use the token exactly as given. A column token that matches no column on the campaign’s lists renders as nothing, which leaves a gap recipients notice.

Watch it run

Opens are only counted while open tracking is on, and it is off by default. Set openRateTrackingEnabledAt on the campaign to turn it on.

Change the source lists

PATCH /business/campaigns/{campaignId} updates a campaign’s settings, listIds among them. The new set replaces the old one and is held to the same rule as create: together, the lists must contain at least one contact reachable on every channel in the sequence, otherwise the request answers 422 LIST_INCOMPATIBLE_WITH_CHANNELS and nothing changes.
For an AI-generated campaign, wait until initializationStatus is completed before changing listIds: the check reads the campaign’s generated steps, so while initialization is still running the request answers 409 CAMPAIGN_INITIALIZING. Poll and retry. Changing the lists on a running campaign does not by itself enroll the newly added list’s contacts, unless the campaign is dynamic (isDynamic: true), in which case its next refresh enrolls them.

Stop and copy

POST /business/campaigns/{campaignId}/stop halts an active campaign. Queued messages stop going out; nothing already sent is affected. To resume a stopped campaign, call approve again: contacts pick up where they stopped. POST /business/campaigns/{campaignId}/duplicate copies a campaign as a fresh draft — sequence, settings and copy, without the leads or the history:
The copy is ready to edit straight away, AI campaigns included. It keeps the source lists, schedule, AI settings and exclusions, with one exception: excludeCompanyLists starts empty, so set it again if the original kept customers out. campaignStartDate is copied as it was, so a copy of an older campaign can start sending as soon as you approve it. Duplicating is the safe way to iterate on a campaign that is already running: change the copy, and start the copy. Follow up on replies and clicks uses it to build a second touch for people who clicked but never replied. A saved template you no longer want goes with DELETE /business/campaign-templates/{campaignTemplateId}.

Where to next

Knowledge hubs

Give AI campaigns a curated source of product facts.

Custom columns

Attach per-contact data your steps can merge with column tokens.

Build a list from search

Fill a campaign-ready list from prospect search.

Upload your contacts

Bring your own CRM contacts into a list first.