Overview
UsePOST /v1/campaigns to create a draft campaign from the public steps format.
This endpoint is designed for external integrations. You send a single ordered steps array and Enginy compiles it into the internal campaign graph.
Quick Start
- Start
stepswith the first action that should happen. - Add each next action in the exact order it should run.
- Use
conditionto branch on lead data. - Use
linkedin_connectionto send a connection request and then branch on acceptance. - Put shared continuation steps after the branch instead of duplicating them inside both sides.
Rules
- Build the campaign as an ordered
stepsarray from first action to last action. - Use
conditionandlinkedin_connectionwhen you need branches. - Put shared follow-up work after the branching step instead of duplicating the same steps in both branches.
- Use
{ "type": "end" }only when that branch should stop completely. waitForAcceptance.unitmust always bedays.waitForAcceptance.valuemust be an integer greater than or equal to1.- Validation errors return full paths such as
steps[0].onTrue[1].subject.
Step Types
email.subjectis required for the first email on every live path; follow-up emails in the same thread can omit it.linkedin_connection.waitForAcceptanceis optional — omit it (and the branches) for a fire-and-forget connection request that just sends the invite and continues with whatever follows.add_to_another_campaign.campaignIdmust reference a campaign owned by the same client as the API key.
linkedin_message_bundle
Sends several LinkedIn messages back-to-back in the same step. Each entry in messages can carry text, an attachment, or both:
linkedin_voice_message
Sends a LinkedIn voice message. You can either generate audio from text via text-to-speech (content + voiceId) or provide a pre-recorded audio attachment (attachment with contentType: "AUDIO"). Use GET /v1/voices to discover valid voiceId values (system voices and identity-cloned voices owned by the client).
The step must satisfy one of: (a) both
content and voiceId are provided so we synthesize speech, or (b) attachment is provided to send a pre-recorded audio file. voiceSettings only applies in mode (a).
voiceSettings fields (all optional):
Branching Step Types
Condition Types
condition.type supports exactly these values:
lead_field lets you branch on any built-in column or custom field. operator accepts: EQUALS, NOT_EQUALS, CONTAINS, NOT_CONTAINS, GREATER_THAN, LESS_THAN, GREATER_THAN_OR_EQUALS, LESS_THAN_OR_EQUALS, IS_EMPTY, IS_NOT_EMPTY. value is required for every operator except IS_EMPTY and IS_NOT_EMPTY.
Timed Conditions (waitFor)
email_opened, email_clicked, task_completed, and connection_accepted require a waitFor object on the condition:
waitFor.valuemust be a positive number.waitFor.unitmust be one ofseconds,minutes,hours, ordays.email_openedandemail_clickedmust be placed immediately after anemailstep.task_completedmust be placed immediately after ataskstep.connection_acceptedchecks whether the lead has accepted a LinkedIn connection request that was sent earlier in the campaign. Use this when you want to fan out work after the request without inlining the acceptance check on thelinkedin_connectionstep itself.
Validation Checklist
stepsmust contain at least one step.- Every branch array you provide must contain at least one step.
- Use
{ "type": "end" }if a branch should stop explicitly. waitForAcceptance.unitmust always bedays.waitForAcceptance.valuemust be a whole integer greater than or equal to1.- If
GET /v1/tasks/ownersreturns owners, everytaskstep must include a validownerId. - Every
linkedin_voice_messagestep must reference avoiceIdreturned byGET /v1/voices.
Task Owners
If your campaign containstask steps, call GET /v1/tasks/owners first.
- If that endpoint returns owners, every
taskstep must include a validownerId. - If no owners are returned,
ownerIdcan be omitted.
Voices
If your campaign containslinkedin_voice_message steps, call GET /v1/voices to discover the available voiceId values:
source: "system"voices are available to every client.source: "identity"voices are cloned from one of the client’s identities.- A
voiceIdthat is not in the list will fail validation when creating or validating the campaign.
Related Endpoints
POST /v1/campaignscreates the draft campaign.GET /v1/campaignslists campaigns after creation.GET /v1/tasks/ownersreturns the valid task owners fortasksteps.GET /v1/voicesreturns the valid voices forlinkedin_voice_messagesteps.POST /v1/add-contact-to-campaignadds one contact to an existing campaign.POST /v1/add-contact-group-to-campaignadds every contact in a contact group to an existing campaign.
Adding Contacts After Creation
Use the campaign creation endpoint to build the sequence first, then use one of the audience endpoints below to start adding contacts to it.POST /v1/add-contact-to-campaignis for one contact at a time.POST /v1/add-contact-group-to-campaignis for an entire contact group and returns counts for newly added, reactivated, already-present, and skipped contacts.