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 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 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 id     and Degree     are both supplied, Dux-Soup 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 resolves the profile and schedules the first action once the extension picks up the request. The response still returns success: true    , but data.newtags     is an empty array.
  • Already enrolled - if id        is 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.

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 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 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-out      to 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'