Campaign Management API

Overview


The  Campaign Management API lets you create, inspect, update, and control Campaigns. 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 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 guidance on calculating the signature, please refer to 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 curl  commands 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 Fixed pre-paid plans with 2+ seats.

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 or STACKED 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 API can resolve about the profile at the moment the request is submitted:

  • Immediate execution - if id and Degree are both supplied, the robot recognizes the profile straight away and schedules the first Campaign action immediately. The response includes a system tag in data.newtags in the form {{CAMPAIGNID}}-enrolled   (e.g., 🦆-default-enrolled ).
  • Queued - if id is omitted, or Degree is omitted, the enroll request is placed in the queue instead of scheduling campaign actions immediately; Dux-Soup API resolves the profile and schedules the first action once the robot picks up the request. The response still returns success: true, but data.newtags is an empty array.
  • Already enrolled - if id  is supplied and the API response 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, the robot can't detect a duplicate at submission time.

Degree isn'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: 1 for 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 or STACKED 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 profile object in Enroll Profile into Campaign above (id, Profile, Degree) - use this form when you want to supply Degree, 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'

profileid accepts 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-in  to the profile. Because the  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-out   to the profile. Because the 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.

The robot 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'