Campaigns / REST API
Create campaign
Create a draft campaign with a required explicit workflow_definition and assigned_accounts to select senders. UI Easy Mode generates a graph from its selected options; machine creation never selects that template implicitly. This never sends. Campaign delivery graphs are distinct from Agent Workflows. Supply the complete nodes and edges to create-campaign or update-campaign-workflow. Start -> optional icp_scoring -> outreach. If scoring is present, all outreach paths must pass qualified; not_qualified ends without sending. Scoring must precede all sends or email campaign pushes. is_open_profile requires confirmed status before outreach: true -> yes -> inmail with only_open_profiles:true; false -> no -> connection_request with its usual accepted/no_response branches. Missing status triggers a quota-aware profile refresh; failed, limited or incomplete checks wait at this node without outreach. Unknown never means false. No hidden routing occurs at connection_request. Give each terminal branch its own End node. connection_request has accepted and no_response outputs. accepted continues to optional messages or End. no_response fires after wait_for_response_days and can go to optional cancel_invitation -> End, or an explicitly requested InMail/email fallback. Never withdraw an accepted invitation. message, template_message, enhanced_message and inmail have replied and no_reply outputs. Every replied output goes directly to End. no_reply waits reply_wait_days, then goes to an optional follow-up or End. Do not add a second delay for that same waiting period. A/B testing works with direct prospect imports as well as Tables: import customFields.message_1a and customFields.message_1b (or CSV columns with those exact names), then reference {{message_1a}} and {{message_1b}} in the node variants. No Table is required. Each variable value is the complete rendered message. A/B testing is off by default. Set ab_testing_enabled:true only with explicitly authored variants referencing different message variables (for example {{message_1a}} and {{message_1b}}); never invent message variants or distribution defaults. With ab_testing_enabled:false only message_template is sent. Withdrawal, scoring, InMail, follow-ups and email destinations are optional; never add them unless requested. A connection-only graph wires accepted and no_response to End. instantly, smartlead and emailbison require credential_id and campaign_id for the selected external campaign. InMail requires a Sales Navigator sender; open profiles can use free InMail subject to provider limits. No cycles, dangling outputs or unreachable nodes. Every branch terminates at End. Saving creates a draft only; inspect the saved graph and obtain launch authorization before starting.
POST /api/campaignsDeterministic operationParameters
workspaceIdRequired · string- See the input schema for this field.
nameRequired · string- See the input schema for this field.
descriptionOptional · string- See the input schema for this field.
assigned_accountsOptional · array- See the input schema for this field.
senderAccountIdsOptional · array- Legacy alias for assigned_accounts.
workflow_definitionRequired · object- Campaign delivery graphs are distinct from Agent Workflows. Supply the complete nodes and edges to create-campaign or update-campaign-workflow. Start -> optional icp_scoring -> outreach. If scoring is present, all outreach paths must pass qualified; not_qualified ends without sending. Scoring must precede all sends or email campaign pushes. is_open_profile requires confirmed status before outreach: true -> yes -> inmail with only_open_profiles:true; false -> no -> connection_request with its usual accepted/no_response branches. Missing status triggers a quota-aware profile refresh; failed, limited or incomplete checks wait at this node without outreach. Unknown never means false. No hidden routing occurs at connection_request. Give each terminal branch its own End node. connection_request has accepted and no_response outputs. accepted continues to optional messages or End. no_response fires after wait_for_response_days and can go to optional cancel_invitation -> End, or an explicitly requested InMail/email fallback. Never withdraw an accepted invitation. message, template_message, enhanced_message and inmail have replied and no_reply outputs. Every replied output goes directly to End. no_reply waits reply_wait_days, then goes to an optional follow-up or End. Do not add a second delay for that same waiting period. A/B testing works with direct prospect imports as well as Tables: import customFields.message_1a and customFields.message_1b (or CSV columns with those exact names), then reference {{message_1a}} and {{message_1b}} in the node variants. No Table is required. Each variable value is the complete rendered message. A/B testing is off by default. Set ab_testing_enabled:true only with explicitly authored variants referencing different message variables (for example {{message_1a}} and {{message_1b}}); never invent message variants or distribution defaults. With ab_testing_enabled:false only message_template is sent. Withdrawal, scoring, InMail, follow-ups and email destinations are optional; never add them unless requested. A connection-only graph wires accepted and no_response to End. instantly, smartlead and emailbison require credential_id and campaign_id for the selected external campaign. InMail requires a Sales Navigator sender; open profiles can use free InMail subject to provider limits. No cycles, dangling outputs or unreachable nodes. Every branch terminates at End. Saving creates a draft only; inspect the saved graph and obtain launch authorization before starting.
curl -X POST "https://app.pipeline.help/api/campaigns" \
-H "Authorization: Bearer $PIPELINE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"example","workspaceId":"00000000-0000-4000-8000-000000000000","workflow_definition":{"nodes":[{"id":"00000000-0000-4000-8000-000000000000","type":"start","position":{"x":1,"y":1},"data":{}}],"edges":[{"id":"00000000-0000-4000-8000-000000000000","source":"example","target":"example"}]}}'Full input schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"description": {
"type": "string",
"maxLength": 2000
},
"assigned_accounts": {
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"senderAccountIds": {
"description": "Legacy alias for assigned_accounts.",
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"workflow_definition": {
"type": "object",
"properties": {
"nodes": {
"minItems": 1,
"maxItems": 500,
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string",
"enum": [
"start",
"end",
"website_visitor_trigger",
"new_connection_trigger",
"post_keyword_trigger",
"icp_scoring",
"connection_request",
"cancel_invitation",
"message",
"template_message",
"enhanced_message",
"inmail",
"delay",
"condition",
"is_connected",
"is_open_profile",
"profile_visit",
"follow",
"like_post",
"post_comment_reply",
"research_agent",
"reply_agent",
"whatsapp_message",
"trykitt",
"findymail",
"leadmagic",
"icypeas",
"prospeo",
"quickenrich",
"instantly",
"smartlead",
"emailbison",
"webhook",
"exa",
"firecrawl",
"spider",
"http_request",
"google_sheets",
"slack_notification",
"openai_processor",
"claude_processor"
],
"description": "Supported campaign delivery node types. Withdrawal is cancel_invitation, not cancel_connection_request. These are distinct from Agent Workflow play nodes."
},
"position": {
"type": "object",
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
}
},
"required": [
"x",
"y"
],
"additionalProperties": false
},
"data": {
"type": "object",
"properties": {
"message_template": {
"type": "string"
},
"outputVariable": {
"type": "string"
},
"subject": {
"type": "string"
},
"post_url": {
"type": "string"
},
"keyword": {
"type": "string"
},
"reply_message": {
"type": "string"
},
"customInstructions": {
"type": "string"
},
"send_empty_request": {
"type": "boolean"
},
"only_open_profiles": {
"type": "boolean"
},
"ab_testing_enabled": {
"description": "Explicit opt-in. False sends only message_template. True requires at least two authored variants. Omit only to preserve legacy saved variant behavior.",
"type": "boolean"
},
"variants": {
"description": "Authored A/B variants. Example: [{id:\"a\",name:\"A\",type:\"template\",content:\"{{message_1a}}\",weight:50},{id:\"b\",name:\"B\",type:\"template\",content:\"{{message_1b}}\",weight:50}].",
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"name": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string",
"enum": [
"template",
"framework"
]
},
"content": {
"description": "For template variants, one whole message variable, for example {{message_1a}}. Each variant must use a distinct variable containing the complete pre-rendered message.",
"type": "string"
},
"subject": {
"type": "string"
},
"framework": {
"type": "string",
"enum": [
"casual_question",
"direct_pitch",
"priority_check",
"lead_magnet",
"pain_point",
"case_study",
"partnership",
"advanced_research",
"worldview_alignment",
"diagnostic",
"bet_on_you",
"alpha_opening"
]
},
"weight": {
"type": "number",
"description": "Explicit distribution percentage. Enabled tests require positive weights totaling 100. No variants or weights are inserted automatically."
}
},
"required": [
"id",
"name",
"type",
"weight"
],
"additionalProperties": {}
}
},
"icpThreshold": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"thresholdOperator": {
"type": "string",
"enum": [
">=",
">",
"<=",
"<",
"=="
]
},
"wait_for_response_days": {
"type": "number",
"exclusiveMinimum": 0
},
"reply_wait_days": {
"type": "number",
"exclusiveMinimum": 0
},
"credential_id": {
"type": "string"
},
"campaign_id": {
"type": "string"
}
},
"additionalProperties": {},
"description": "Node config: icp_scoring {icpThreshold:0..100, thresholdOperator:\">=\", outputVariable:\"icp_score\"}; connection_request {send_empty_request:boolean, message_template:string, wait_for_response_days:positive number}; message/template_message {message_template:string, reply_wait_days:positive number}; inmail {subject:string, message_template:string, reply_wait_days:positive number, only_open_profiles:boolean}; cancel_invitation {}; delay {delay_type:\"minutes\"|\"hours\"|\"days\", delay_amount:positive number}; instantly/smartlead/emailbison {credential_id:string, campaign_id:string, field_mappings:object, custom_variables:object}. Templates use {{fieldName}} from supplied prospect customFields; nested templates must be rendered before import."
}
},
"required": [
"id",
"type",
"position",
"data"
],
"additionalProperties": {}
}
},
"edges": {
"maxItems": 2000,
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"source": {
"type": "string",
"minLength": 1
},
"target": {
"type": "string",
"minLength": 1
},
"sourceHandle": {
"description": "Required for branching nodes: icp_scoring qualified/not_qualified; connection_request accepted/no_response; messages and InMail replied/no_reply; is_open_profile yes/no. Omit for single-output nodes. One edge per output handle.",
"type": "string"
}
},
"required": [
"id",
"source",
"target"
],
"additionalProperties": {}
}
}
},
"required": [
"nodes",
"edges"
],
"additionalProperties": false,
"description": "Campaign delivery graphs are distinct from Agent Workflows. Supply the complete nodes and edges to create-campaign or update-campaign-workflow. Start -> optional icp_scoring -> outreach. If scoring is present, all outreach paths must pass qualified; not_qualified ends without sending. Scoring must precede all sends or email campaign pushes. is_open_profile requires confirmed status before outreach: true -> yes -> inmail with only_open_profiles:true; false -> no -> connection_request with its usual accepted/no_response branches. Missing status triggers a quota-aware profile refresh; failed, limited or incomplete checks wait at this node without outreach. Unknown never means false. No hidden routing occurs at connection_request. Give each terminal branch its own End node. connection_request has accepted and no_response outputs. accepted continues to optional messages or End. no_response fires after wait_for_response_days and can go to optional cancel_invitation -> End, or an explicitly requested InMail/email fallback. Never withdraw an accepted invitation. message, template_message, enhanced_message and inmail have replied and no_reply outputs. Every replied output goes directly to End. no_reply waits reply_wait_days, then goes to an optional follow-up or End. Do not add a second delay for that same waiting period. A/B testing works with direct prospect imports as well as Tables: import customFields.message_1a and customFields.message_1b (or CSV columns with those exact names), then reference {{message_1a}} and {{message_1b}} in the node variants. No Table is required. Each variable value is the complete rendered message. A/B testing is off by default. Set ab_testing_enabled:true only with explicitly authored variants referencing different message variables (for example {{message_1a}} and {{message_1b}}); never invent message variants or distribution defaults. With ab_testing_enabled:false only message_template is sent. Withdrawal, scoring, InMail, follow-ups and email destinations are optional; never add them unless requested. A connection-only graph wires accepted and no_response to End. instantly, smartlead and emailbison require credential_id and campaign_id for the selected external campaign. InMail requires a Sales Navigator sender; open profiles can use free InMail subject to provider limits. No cycles, dangling outputs or unreachable nodes. Every branch terminates at End. Saving creates a draft only; inspect the saved graph and obtain launch authorization before starting."
}
},
"required": [
"name",
"workspaceId",
"workflow_definition"
],
"additionalProperties": false
}