curl --request POST \
--url https://api.tryfuse.ai/api/v1/business/campaigns \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"campaignName": "<string>"
}
'import requests
url = "https://api.tryfuse.ai/api/v1/business/campaigns"
payload = { "campaignName": "<string>" }
headers = {
"Authorization": "Basic <encoded-value>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Basic <encoded-value>', 'Content-Type': 'application/json'},
body: JSON.stringify({campaignName: '<string>'})
};
fetch('https://api.tryfuse.ai/api/v1/business/campaigns', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"campaignId": "6a8dce146dc0b3d9029c22d0",
"status": "initializing"
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}Create a draft campaign
Creates a draft campaign in status initializing; nothing is sent until you call POST /business/campaigns//approve. campaignType: manual (the default) scaffolds one empty step per entry in channels immediately (sequenceNumber 0, 1, 2 …), so you can list them with GET …/steps and write subject/body with PATCH …/steps/. campaignType: ai-generated returns immediately and runs prompt analysis and topic generation in the background: poll GET /business/campaigns/ until initializationStatus is completed (or failed, with the reason in initializationError) before editing or approving. Passing templateId copies that template’s steps and channels for either type. The campaign is owned by the token owner. No credits are charged by this call. Rate limit: 30 requests/minute and 1,000/day per token owner, shared by every campaign, scheduled-send, campaign-template and knowledge-hub endpoint.
Errors:
404LIST_NOT_FOUND— A listId/listIds entry does not exist, is archived, or belongs to another team.404TEMPLATE_NOT_FOUND— templateId does not exist or is not visible to you.404WRITING_STYLE_NOT_FOUND— writingStyleId (ai-generated only) is not one of your writing styles.404KNOWLEDGE_HUB_NOT_FOUND— knowledgeHubId (ai-generated only) is not one of your non-archived knowledge hubs.422INVALID_CAMPAIGN_CHANNELS— More than one linkedin_connection step, or a linkedin_connection after a linkedin_message (also evaluated on the template’s steps when templateId is given).422LIST_INCOMPATIBLE_WITH_CHANNELS— The source lists are empty, or no contact carries an email address (email/inmail) or a LinkedIn URL (LinkedIn channels) for the requested channels.422EXCLUDE_COMPANY_LISTS_INVALID— An excludeCompanyLists entry is not a non-archived company or people list owned by your team.422VALIDATION_FAILED— The body failed schema validation (unknown key, both or neither of listId/listIds, channels together with templateId, an AI-only field on a manual campaign, an unrecognised timezone, a non-http(s) ctaLink);paramnames the field.429RATE_LIMITED— More than 30 campaign requests in a minute, or 1,000 in a day, for this token owner (the bucket is shared by every /business/campaigns, /business/scheduled-sends, /business/campaign-templates and /business/knowledge-hubs call).500UNEXPECTED_ERROR— An unhandled failure; the detail stays in our logs and is never returned.
Requires one of the following token scopes: campaigns.
curl --request POST \
--url https://api.tryfuse.ai/api/v1/business/campaigns \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"campaignName": "<string>"
}
'import requests
url = "https://api.tryfuse.ai/api/v1/business/campaigns"
payload = { "campaignName": "<string>" }
headers = {
"Authorization": "Basic <encoded-value>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Basic <encoded-value>', 'Content-Type': 'application/json'},
body: JSON.stringify({campaignName: '<string>'})
};
fetch('https://api.tryfuse.ai/api/v1/business/campaigns', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"campaignId": "6a8dce146dc0b3d9029c22d0",
"status": "initializing"
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"param": "<string>",
"doc_url": "<string>",
"request_id": "<string>"
}
}Authorizations
Your API token (af_…) as the Basic-auth username, with an empty password.
Body
Display name of the campaign (1-200 characters, trimmed); also the stem of the CSV export filename.
1 - 200Id of the single Fuse list the campaign sources contacts from; mutually exclusive with listIds (exactly one of the two is required). The list must belong to your team and not be archived, else 404 LIST_NOT_FOUND.
Ids of 1-10 Fuse lists the campaign sources; mutually exclusive with listId. Every list must belong to your team and not be archived, else 404 LIST_NOT_FOUND. Take the ids from GET /business/lists with entityType=contactList — a campaign enrolls contacts. The lists are OR-joined into a deduplicated union: they are read in the order given and a contact that sits in two of them is enrolled once, up to the campaign's 10000-contact cap, after which the remaining lists are skipped.
1 - 10 elementsA Fuse list id (24-character hex ObjectId), as the id of a GET /business/lists row.
Ordered channel scaffold: one empty sequence step (sequenceNumber 0, 1, 2 ...) is created per entry, 1-10 entries, default ["email"]. At most one linkedin_connection, and it must precede every linkedin_message (422 INVALID_CAMPAIGN_CHANNELS). Forbidden together with templateId, whose steps decide the channels.
1 - 10 elementsA step channel: email, linkedin_connection (connection request with optional note), linkedin_message (message to an accepted connection) or inmail (LinkedIn InMail, consumes the sender's InMail credits).
email, linkedin_connection, linkedin_message, inmail ISO 8601 date-time before which nothing is sent (default: now); evaluated in timezone together with emailDays.
Time zone in which the daily sending window (09:00-17:00 local) and emailDays are evaluated; default UTC. Accepted values are IANA time zone names, for example America/New_York, Europe/Berlin, Asia/Kolkata or UTC. Do not send an abbreviation: EST is in the tz database but resolves to a fixed UTC-5 zone that never observes daylight saving, so name the region instead. A name the tz database does not know is rejected rather than silently evaluated as UTC.
Weekdays on which sends may go out; default Monday to Friday. One of exactly: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday — capitalised English names, nothing else. The days are OR-joined: a send that comes due is pushed forward to the next day named in the set, so a weekday you leave out is never used. 1-7 unique names; naming all seven removes the weekday restriction.
1 - 7 elementsAn English weekday name with a capital first letter (Monday ... Sunday).
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday Ids of up to 10 Fuse people lists whose members are excluded from enrollment (a list that is also a source list is ignored here); default []. Take the ids from GET /business/lists with entityType=contactList. The lists are OR-joined: a contact is skipped when it appears in any one of them, matched on contact id, email address (case-insensitively) or LinkedIn URL. These ids are stored without an ownership check, so an id that is not one of your lists is accepted and silently excludes nobody — and a companyList here excludes nobody either, use excludeCompanyLists for that.
10A Fuse list id (24-character hex ObjectId), as the id of a GET /business/lists row.
Ids of up to 20 company or people lists owned by your team whose companies' contacts are skipped at enrollment; default []. Take the ids from GET /business/lists — either entityType: a companyList contributes its companies, a contactList contributes the companies its contacts work at. The lists are OR-joined: a contact is skipped when its company appears in any one of them, matched by company id and by the company's web domain (personal-email domains are never used). Unlike excludeLists these ids are checked, so one that is unknown, archived or not your team's answers 422 EXCLUDE_COMPANY_LISTS_INVALID.
20A Fuse list id (24-character hex ObjectId), as the id of a GET /business/lists row.
Skips contacts your campaigns already reached: none keeps them, ever excludes anyone ever messaged, last_1_month / last_3_months / last_6_months / last_1_year exclude those messaged within that window; contacts with a pending send in an active campaign are always excluded. Default none.
none, ever, last_1_month, last_3_months, last_6_months, last_1_year When true, contacts who have already replied to one of your campaigns are excluded from enrollment. Default false.
When true, contacts added to the source lists after activation are enrolled automatically by a background refresh. Default false.
When true, each contact's recent LinkedIn posts are fetched at activation and fed to AI personalization (needs a LinkedIn URL on the contact). Default false.
When true, every email step appends a one-click unsubscribe footer (email channel only). Default true.
ISO 8601 timestamp that switches on the open-tracking pixel for outgoing emails (it records when tracking was enabled); null (default) keeps open tracking off.
ISO 8601 timestamp from which enrollment only accepts contacts whose email verified as valid (catch-all and never-verified uploaded addresses are skipped); null (default) also allows catch-all and never-verified uploaded emails. Applies to enrollment only.
User ids of teammates allowed to view and edit this campaign in the app besides you; default []. Take each id from the id of a GET /business/team/members row (a row whose id is null has no linked user account and cannot be a delegate). Access is OR-joined — any one of the listed users gets it — and there is no cap on how many you list. Nothing checks the ids against your team on the way in, and the app's delegate test is a plain membership check on this array that runs ahead of every team rule, so an id belonging to any real Fuse user — teammate or not — grants that user the access the owner has: opening the campaign, editing its settings and steps, activating it so it sends, and seeing it in their own campaign list. Only a well-formed id that matches no user grants nobody anything. The grant stops at the app: every campaign endpoint here resolves the token owner's own campaigns, so a delegate calling with their own key still gets 404.
A Fuse user id (24-character hex ObjectId) of a teammate, as the id of a GET /business/team/members row.
manual (default): you write every step's subject/body and the draft is ready to author immediately. ai-generated: prompt analysis and topic generation run in the background; poll GET /business/campaigns/{campaignId} until initializationStatus is completed before editing or approving.
ai-generated, manual Id of a saved campaign template (GET /business/campaign-templates) whose steps are copied into the new campaign; its channels replace the channels field, so the two cannot be combined. null means no template. An unknown or inaccessible template answers 404 TEMPLATE_NOT_FOUND.
ai-generated only: free-text brief (up to 5000 characters) describing the offer and goal; the AI analyses it to derive the campaign topics. Forbidden for manual campaigns.
5000ai-generated only: up to 10 URLs whose page content grounds the generated copy. Forbidden for manual campaigns.
10An absolute http(s) URL (up to 2000 characters).
2000ai-generated only: free text in your own words (up to 10000 characters) — product details, positioning, proof points; there is no fixed set of values. It is stored as one note on the knowledge profile built for this campaign, alongside websiteUrls, and grounds the generated copy. Forbidden for manual campaigns.
10000The campaign's call-to-action link, honoured for either campaign type; null or an empty string means no link. Accepted values: one absolute URL whose scheme is http:// or https:// (up to 2000 characters); anything else, a bare domain or a mailto: link included, is rejected. The URL is inserted verbatim wherever a step's text uses {CTA Link} or one of its aliases {Calendar Link}, {cta_link}, {calendar_link}, {{calendarLink}}.
2000ai-generated only: id of one of your writing styles whose rules steer the generated copy; null or omitted uses your default style; an unknown id answers 404 WRITING_STYLE_NOT_FOUND. Forbidden for manual campaigns.
ai-generated only: id of the knowledge hub (GET /business/knowledge-hubs) that grounds the generated content; omitted means your default hub; an unknown id answers 404 KNOWLEDGE_HUB_NOT_FOUND. Forbidden for manual campaigns.