curl --request POST \
--url https://api.tryfuse.ai/api/v1/business/campaigns/{campaignId}/steps \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"sequenceNumber": 25,
"daysBetween": 45
}
'import requests
url = "https://api.tryfuse.ai/api/v1/business/campaigns/{campaignId}/steps"
payload = {
"sequenceNumber": 25,
"daysBetween": 45
}
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({sequenceNumber: 25, daysBetween: 45})
};
fetch('https://api.tryfuse.ai/api/v1/business/campaigns/{campaignId}/steps', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"step": {
"id": "6a8dce2ef83628aea1088041",
"channel": "email",
"type": "manual",
"sequenceNumber": 1,
"daysBetween": 2,
"title": "probe step subject",
"topic": null,
"subject": "Following up on BrightPay's finance hiring",
"body": "<p>Hi {Contact First Name}, circling back on my note last week.</p>",
"cc": [
"ops@yourcompany.com"
]
}
}{
"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>"
}
}Add a sequence step
Adds one sequence step. sequenceNumber is the step’s 0-based slot - the same numbering GET /business/campaigns//steps reports - and must be free (409 STEP_POSITION_TAKEN); existing steps are not shifted on insert, and only DELETE renumbers. daysBetween is the wait after the previous step (after the campaign start for step 0). type: manual sends your subject/body as written, with tokens and spintax substituted per lead at send time; type: ai_generated writes its own topic and title with AI when the step is created and renders each message per lead (do not send topic); type: ai_reply drafts a reply from the topic you supply and parks it for approval. linkedin_visit and linkedin_like steps carry no message at all. A linkedin_connection step may not follow a linkedin_message step (422 STEP_ORDER_INVALID). Only the token owner may add steps. 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:
404CAMPAIGN_NOT_FOUND— No campaign with this id exists, it belongs to another account (including a campaign delegated to you or shared by your team’s visibility settings), or it has been deleted.409STEP_POSITION_TAKEN— A step already occupies this sequenceNumber in the campaign.422STEP_ORDER_INVALID— A linkedin_connection step would follow a linkedin_message step.422VALIDATION_FAILED— Unknown key, missing channel/sequenceNumber/daysBetween, a value out of range, a topic on an ai_generated step, a missing topic on an ai_reply step, or content on a linkedin_visit / linkedin_like step;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— The step could not be stored, or AI topic generation failed for an ai_generated step.
Requires one of the following token scopes: campaigns.
curl --request POST \
--url https://api.tryfuse.ai/api/v1/business/campaigns/{campaignId}/steps \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"sequenceNumber": 25,
"daysBetween": 45
}
'import requests
url = "https://api.tryfuse.ai/api/v1/business/campaigns/{campaignId}/steps"
payload = {
"sequenceNumber": 25,
"daysBetween": 45
}
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({sequenceNumber: 25, daysBetween: 45})
};
fetch('https://api.tryfuse.ai/api/v1/business/campaigns/{campaignId}/steps', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"step": {
"id": "6a8dce2ef83628aea1088041",
"channel": "email",
"type": "manual",
"sequenceNumber": 1,
"daysBetween": 2,
"title": "probe step subject",
"topic": null,
"subject": "Following up on BrightPay's finance hiring",
"body": "<p>Hi {Contact First Name}, circling back on my note last week.</p>",
"cc": [
"ops@yourcompany.com"
]
}
}{
"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.
Path Parameters
The campaign's id (24-character hex ObjectId), as returned by POST /business/campaigns or as the campaignId of a GET /business/campaigns row.
Body
Step channel: email, linkedin_connection (connection request), linkedin_message (message to an accepted connection), linkedin_visit (profile visit, no content), linkedin_like (reaction to a recent post, no content), inmail (LinkedIn InMail, consumes InMail credits), dialer (phone-call task for a rep) or todo (free-form human task). A linkedin_connection step cannot come after a linkedin_message step (422 STEP_ORDER_INVALID).
email, linkedin_connection, linkedin_message, linkedin_visit, linkedin_like, inmail, dialer, todo The step's 0-based slot in the sequence — the same numbering GET /business/campaigns/{campaignId}/steps reports, so 0 is the first step. Must be unused in this campaign (409 STEP_POSITION_TAKEN); existing steps are not shifted on insert (only DELETE renumbers).
0 <= x <= 50Whole days to wait after the previous step (or after the campaign start for the first step) before this one is due, 0-90.
0 <= x <= 90manual (default) sends your subject/body as written; ai_generated writes a topic and title with AI at creation and renders each message per lead at send time (send no topic — it is generated); ai_reply is an AI-drafted reply that waits for approval and needs a topic.
manual, ai_generated, ai_reply Subject line for a manual step (up to 500 characters, may be empty); becomes the step title. Rejected on linkedin_visit and linkedin_like steps, which carry no message.
500Message body for a manual step (up to 20000 characters; {Variable} tokens and spintax substitute at send time). On a linkedin_connection step this is the invitation note, capped at LinkedIn's 200-character limit. Rejected on linkedin_visit and linkedin_like steps, which carry no message.
Free text: what this step should say, in your own words — there is no fixed set of topics. 1-500 characters. Required for ai_reply, rejected for ai_generated (which generates its own) and for linkedin_visit / linkedin_like steps. Stored but not rendered on a manual step.
1 - 500Accepted values: bare email addresses such as ops@example.com — a display name or angle brackets is rejected, up to 320 characters each. Every address you list is copied on every send of this step, up to 10 addresses. Only an email step actually sends them: on any other channel the value is stored and never used.
10A bare email address, up to 320 characters.
320Response
Success
Show child attributes
Show child attributes