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'