Campaign Management API
Overview
The Dux-Soup Campaign Management API lets you create, inspect, update, and control Campaigns from outside Dux-Soup. This means you can manage campaign definitions and move profiles between campaigns programmatically - for example, creating a new Campaign when a marketing list is uploaded to your CRM, or unenrolling a profile the moment a deal closes.
All Campaign Management API calls are made against your Remote Control endpoint:
https://app.dux-soup.com/xapi/remote/control/{{USERID}}/...
Required fields
All Dux-Soup API requests must include a signed X-Dux-Signature header. For POST and PUT requests, include a JSON body containing targeturl , timestamp , and userid . For comprehensive guidance on obtaining the Authentication Key and calculating the signature, please refer to Connecting to and Authenticating API calls.
| Field | Description |
|---|---|
X-Dux-Signature (header) |
HMAC signature calculated from your Authentication Key |
targeturl |
The target URL of the command (should start with https://app.dux-soup.com ) |
userid |
The userid the command is sent to; should match the userid in the target URL |
timestamp |
Current Unix time in milliseconds; must be within 5 minutes of the current time |
You can generate
curlcommands or execute calls directly at https://app.dux-soup.com/web/rc/test - the easiest way to try any endpoint on this page.
List Campaigns
Returns all Campaigns configured on the account, including their status, actions, and settings.
URL: https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns
HTTP method: GET
Example request
curl -v -XGET -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns'
Example response
{
"campaigns": [
{
"name": "Default",
"id": "default",
"description": "The default campaign",
"actions": [
{
"type": "connect",
"interval": { "days": 0, "hours": 4, "minutes": 0 },
"text": "Hi _FN_, check my blog: https://www.dux-soup.com"
}
],
"created": "2026-07-03T07:43:47.570Z",
"status": "off",
"enrollandtag": false,
"target": "regular",
"modified": null,
"exclusive": false,
"reject_connected_profiles": false,
"smart": true
},
{
"name": "July",
"id": "new-july",
"target": "salesnav",
"description": "2000 from List X",
"actions": [
{
"type": "connect",
"interval": { "days": 0, "hours": 4, "minutes": 0 },
"text": "Hi _FN_, it would be great to connect."
},
{
"type": "message",
"interval": { "days": 0, "hours": 4, "minutes": 0 },
"text": "What do you think about our new Dash?"
}
],
"status": "on",
"smart": true,
"exclusive": true,
"enrollandtag": true,
"reject_connected_profiles": true
}
]
}
Get Campaign
Returns the details of a single Campaign.
URL: https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns/{{CAMPAIGNID}}
HTTP method: GET
Example request
curl -v -XGET -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns/default'
Response format is the same as a single entry in the campaigns array from List Campaigns above.
Create Campaign
Creates a new Campaign.
URL: https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns
HTTP method: POST
HTTP body: a JSON object with the following attributes, in addition to the required fields.
| Field | Description |
|---|---|
campaign |
Campaign object (mandatory, Object) - see attributes below |
Campaign object attributes
| Field | Description |
|---|---|
name |
Unique Campaign Name (mandatory, String) |
id |
Unique Campaign ID (mandatory, String) |
target |
"regular" , "recruiter" or "salesnav" (mandatory, String) |
description |
Free-text description of the Campaign (optional, String) |
actions |
Array of action objects (type , interval , text ) defining the Campaign steps (mandatory, Array) |
status |
"on" or "off" (mandatory, String) |
smart |
Enable AI personalization (optional, Boolean) |
exclusive |
Reject profiles from other campaigns (optional, Boolean) |
enrollandtag |
Automatically tag profiles with campaignid on enrollment (optional, Boolean) |
reject_connected_profiles |
Exclude profiles already connected (optional, Boolean) |
teamaware |
Make the Campaign visible/usable across a team (optional, Boolean). Available in Team plans only. |
Example request
curl -v -XPOST -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' -d '{
"targeturl": "https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns",
"userid": "{{USERID}}",
"timestamp": 1783338781722,
"campaign": {
"target": "salesnav",
"description": "2000 from List X",
"actions": [
{ "type": "connect", "interval": { "days": 0, "hours": 4, "minutes": 0 }, "text": "Hi _FN_, it would be great to connect." },
{ "type": "message", "interval": { "days": 0, "hours": 4, "minutes": 0 }, "text": "What do you think about our new Dash?" }
],
"status": "on",
"smart": true,
"exclusive": true,
"enrollandtag": true,
"reject_connected_profiles": true,
"id": "3rd-degree June"
}
}' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns'
Example response
{
"name": "July",
"id": "new-july",
"target": "salesnav",
"description": "2000 from List X",
"actions": [
{ "type": "connect", "interval": { "days": 0, "hours": 4, "minutes": 0 }, "text": "Hi _FN_, it would be great to connect." },
{ "type": "message", "interval": { "days": 0, "hours": 4, "minutes": 0 }, "text": "What do you think about our new Dash?" }
],
"status": "on",
"smart": true,
"exclusive": true,
"enrollandtag": true,
"reject_connected_profiles": true,
"teamaware": true
}
Update Campaign
Updates an existing Campaign. The full Campaign object must be supplied - partial updates are not supported, so include every field even if only one is changing.
URL: https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns/{{CAMPAIGNID}}
HTTP method: PUT
HTTP body: a JSON object with the following attributes, in addition to the required fields.
Example request
curl -v -XPUT -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' -d '{ "targeturl": "https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns/default", "userid": "{{USERID}}", "timestamp": 1783422575166, "campaign": { "name": "Default", "id": "default", "description": "The default campaign", "actions": [ { "type": "connect", "interval": { "days": 0, "hours": 4, "minutes": 0 }, "text": "Hi _FN_, let'\''s connect " } ], "created": "2026-07-03T07:43:47.570Z", "status": "off", "enrollandtag": false, "target": "regular", "modified": null, "exclusive": false, "reject_connected_profiles": false, "smart": true } }' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns/default'
Example response
{ "success": true, "data": { "name": "Default", "id": "default", "description": "The default campaign", "actions": [ { "type": "connect", "interval": { "days": 0, "hours": 4, "minutes": 0 }, "text": "Hi _FN_, let's connect " } ], "created": "2026-07-03T07:43:47.570Z", "status": "off", "enrollandtag": false, "target": "regular", "modified": null, "exclusive": false, "reject_connected_profiles": false, "smart": true } }
Delete Campaign
Deletes a Campaign.
URL: https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns/{{CAMPAIGNID}}
HTTP method: DELETE
HTTP body: a JSON object with the required fields only.
Example request
curl -v -XDELETE -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' -d '{
"targeturl": "https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns/3rd-degree-june",
"userid": "{{USERID}}",
"timestamp": 1783340261152
}' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns/3rd-degree-june'
Enroll Profile into Campaign
Enrolls a profile into a Campaign.
URL: https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/{{CAMPAIGNID}}/enroll
HTTP method: POST
HTTP body: a JSON object with the following attributes, in addition to the required fields.
Profile object attributes
| Field | Description |
|---|---|
id |
Dux-Soup internal profile ID (optional, String). When supplied, Dux-Soup can check immediately whether the profile is already enrolled in this Campaign, and - together with Degree - can schedule the first Campaign action right away instead of queuing the request. |
Profile |
LinkedIn profile URL (optional, String). Required if id is not supplied. |
Degree |
Connection degree of the profile relative to the account, e.g. 1 , 2 , 3 (optional, Number). Determines which type of first Campaign action can be scheduled immediately - see behavior notes below. |
At least one of id or Profile must be supplied.
Example request
curl -v -XPOST -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' -d '{ "targeturl": "https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/default/enroll", "userid": "{{USERID}}", "timestamp": 1783423784876, "profile": { "id": "id.548182024", "Profile": "https://www.linkedin.com/in/gin-kuz/", "Degree": 2 } }' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/default/enroll'
Example response
{"success":true,"data":{"newtags":["🦆-default-enrolled"]}}
Behavior notes
The response depends on how much Dux-Soup can resolve about the profile at the moment the request is submitted:
- Immediate execution - if
idandDegreeare both supplied, Dux-Soup recognizes the profile straight away and schedules the first Campaign action immediately. The response includes a system tag indata.newtagsin the form{{CAMPAIGNID}}-enrolled(e.g.🦆-default-enrolled). - Queued - if
idis omitted, orDegreeis omitted, the enroll request is placed in the queue instead of scheduling campaign actions immediately; Dux-Soup resolves the profile and schedules the first action once the extension picks up the request. The response still returnssuccess: true, butdata.newtagsis an empty array. - Already enrolled - if
idis supplied and Dux-Soup can already tell the profile was previously enrolled in this Campaign, the call fails immediately:
{"success":false,"message":"Profile was previously enrolled into the target campaign"}
This duplicate check can only happen when id is known; without it, Dux-Soup can't detect a duplicate at submission time.
Degreeisn't validated against the profile's real connection degree at the time of the API call. If the value supplied doesn't match reality (e.g.Degree: 1for a profile that isn't actually a 1st-degree connection), the enroll call itself still succeeds, but the scheduled Campaign action (e.g. a "message" action, which requires 1st degree) will fail - and the Campaign will not progress further for that profile.
Bulk Enroll Profiles
Enrolls multiple profiles into a Campaign in a single call.
URL: https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/{{CAMPAIGNID}}/enrollbatch
HTTP method: POST
HTTP body: a JSON object with the following attributes, in addition to the required fields.
Profile entry formats
Each entry in the profiles array can be either:
- A string, which can be either a Dux-Soup internal profile
id(e.g."id.1234567") or a LinkedIn profile URL (e.g."https://www.linkedin.com/in/jeffweiner08/") - An object with the same attributes as the
profileobject in Enroll Profile into Campaign above (id,Profile,Degree) - use this form when you want to supplyDegree, since the plain-string form doesn't support it
Example request
curl -v -XPOST -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' -d '{ "targeturl": "https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/new-july/enrollbatch", "userid": "{{USERID}}", "timestamp": 1783428952232, "profiles": ["id.123", "https://www.linkedin.com/in/prof/"] }' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/new-july/enrollbatch'
Example response
{ "success": true, "data": [ { "profile": "id.123", "enrolled": true, "tags": [] }, { "profile": "https://www.linkedin.com/in/prof/", "enrolled": true, "tags": [] } ] }
The response returns one result entry per submitted profile, with an enrolled flag and any tags applied for that profile - following the same immediate-vs-queued behavior described under Enroll Profile into Campaign above.
Unenroll Profile from Campaign
Removes a profile from a Campaign.
URL:https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/{{CAMPAIGNID}}/unenroll
HTTP method: POST
HTTP body: a JSON object with the following attributes, in addition to the required fields.
Example request
curl -v -XPOST -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' -d '{
"targeturl": "https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/3rd-degree-june/unenroll",
"userid": "{{USERID}}",
"timestamp": 1783340937755,
"profileid": "https://www.linkedin.com/in/kenneth"
}' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/3rd-degree-june/unenroll'
profileidaccepts a comma-separated list for unenrolling multiple profiles in one call.
Qualify Profile In
Marks a profile as qualified-in for a Campaign. Qualifying is usually a manual, bookkeeping-style action - users can apply it whenever they judge a profile has cleared the lead generation funnel (a positive reply, a successful connection, or any other signal the user considers a qualifying event).
A successful call adds the system tag
🦆-{{CAMPAIGNID}}-qualified-into the profile. Because the Dux-Soup Funnel view is driven by system tags, adding this tag is what moves the profile into the Funnel's Qualified section.
URL: https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/{{CAMPAIGNID}}/qualifyin
HTTP method: POST
HTTP body: a JSON object with the following attributes, in addition to the required fields.
Example request
curl -v -XPOST -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' -d '{
"targeturl": "https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/3rd-degree-june/qualifyin",
"userid": "{{USERID}}",
"timestamp": 1783340951138,
"profileid": "https://www.linkedin.com/in/kenneth"
}' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/3rd-degree-june/qualifyin'
Qualify Profile Out
Marks a profile as qualified-out for a Campaign, without unenrolling it. Typically used when a prospect's reply signals they're not interested (e.g., "I'm not interested")
A successful call adds the system tag
🦆-{{CAMPAIGNID}}-qualified-outto the profile. Because the Dux-Soup Funnel view is driven by system tags, adding this tag is what moves the profile into the Funnel's Bin section.
URL: https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/{{CAMPAIGNID}}/qualifyout
HTTP method: POST
HTTP body: a JSON object with the following attributes, in addition to the required fields.
Example request
curl -v -XPOST -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' -d '{
"targeturl": "https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/3rd-degree-june/qualifyout",
"userid": "{{USERID}}",
"timestamp": 1783340961937,
"profileid": "https://www.linkedin.com/in/kenneth"
}' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/3rd-degree-june/qualifyout'
Both the Qualify In and Qualify Out API calls will stop the drip campaign sequence.
Dux-Soup automatically detects when a prospect replies on LinkedIn, marks the profile as “responded,” and pauses the automated campaign sequence for that profile - regardless of whether you qualified them.
Continue Campaign for Profile
Resumes the automated Campaign sequence for a profile whose sequence was halted by automatic response detection, but whose reply wasn't actually a meaningful stop signal - for example, an ambiguous "Thank you" that got the profile marked as "responded" even though the user wants the Campaign to keep running for them.
URL: https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/{{CAMPAIGNID}}/continue
HTTP method: POST
HTTP body: a JSON object with the following attributes, in addition to the required fields.
Example request
curl -v -XPOST -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' -d '{
"targeturl": "https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/3rd-degree-june/continue",
"userid": "{{USERID}}",
"timestamp": 1783340972771,
"profileid": "https://www.linkedin.com/in/kenneth"
}' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaign/3rd-degree-june/continue'
Switch Profile to Another Campaign
Moves a profile from one Campaign directly into another.
URL: https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns/switch/{{FROM_CAMPAIGNID}}/{{TO_CAMPAIGNID}}
HTTP method: POST
HTTP body: a JSON object with the following attributes, in addition to the required fields.
Example request
curl -v -XPOST -H 'X-Dux-Signature: {{SIGNATURE}}' -H 'Content-type: application/json' -d '{
"targeturl": "https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns/switch/3rd-degree-june/default",
"userid": "{{USERID}}",
"timestamp": 1783340994137,
"profileid": "https://www.linkedin.com/in/kenneth"
}' 'https://app.dux-soup.com/xapi/remote/control/{{USERID}}/campaigns/switch/3rd-degree-june/default'