Browse documentation

Campaigns & sequences

Current release · Updated October 2, 2026

DryKraft campaigns & sequences API: methods, permissions, request fields, response shapes, examples and current limits. Read authentication and error handling first.

GET/api/outreach/campaigns

List campaigns and sequences

Access: Workspace member · Success: 200

Latest 100 with connection_name, enrolled and accepted counts. Accepted includes provider accepted/delivered/read/replied, not proof of delivery.

No request body is required.

Response

Campaign[].

Request shape (illustrative)
curl --request GET \
  --url 'https://app.drykraft.com/api/outreach/campaigns' \
  --cookie 'drykraft_session=<YOUR_SESSION_TOKEN>'
POST/api/outreach/campaigns

Create campaign or sequence draft

Access: Owner, admin or member · Success: 201

Nonfinancial audience <=500 source records. Connection channel must match; no enrollment/send until reviewed launch.

JSON request

Use CampaignInput.

Response

Use Campaign.

Request shape (illustrative)
curl --request POST \
  --url 'https://app.drykraft.com/api/outreach/campaigns' \
  --cookie 'drykraft_session=<YOUR_SESSION_TOKEN>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Example email follow-up",
  "kind": "campaign",
  "channel": "email",
  "object_key": "people",
  "list_id": null,
  "connection_id": "00000000-0000-4000-8000-000000000001",
  "steps": [
    {
      "waitHours": 0,
      "subject": "Hello {{record.data.name}}",
      "body": "Following up on your request."
    }
  ]
}'
GET/api/outreach/campaigns/{id}

Inspect campaign

Access: Workspace member · Success: 200

Includes <=500 enrollments with execution state/error and latest 100 deliveries.

No request body is required.

Response

Use Campaign.

FieldTypeRequiredDetails
enrollmentsobject[]No
deliveriesobject[]No
Request shape (illustrative)
curl --request GET \
  --url 'https://app.drykraft.com/api/outreach/campaigns/00000000-0000-4000-8000-000000000001' \
  --cookie 'drykraft_session=<YOUR_SESSION_TOKEN>'
PUT/api/outreach/campaigns/{id}

Save campaign draft

Access: Owner, admin or member · Success: 200

Only unchanged draft. Launched steps/audience are immutable; create a new draft to revise.

JSON request

FieldTypeRequiredDetails
namestringYesNonblank name Max 100 characters.
kindcampaign | sequenceYesA campaign has exactly one step; a sequence has 1-20.
channelemail | sms | voice | whatsappYesOne channel per campaign/sequence
object_keystringNo Pattern: ^[a-z][a-z0-9_]{1,39}$.
list_idstring or nullNo
connection_iduuidYes
stepsStep[]Yes Min 1 items. Max 20 items.
versionintegerYesPositive optimistic version returned by the latest read. Refresh on 409; do not overwrite stale changes. Min 1.

Response

Use Campaign.

Request shape (illustrative)
curl --request PUT \
  --url 'https://app.drykraft.com/api/outreach/campaigns/00000000-0000-4000-8000-000000000001' \
  --cookie 'drykraft_session=<YOUR_SESSION_TOKEN>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "Example email follow-up",
  "kind": "campaign",
  "channel": "email",
  "object_key": "people",
  "list_id": null,
  "connection_id": "00000000-0000-4000-8000-000000000001",
  "steps": [
    {
      "waitHours": 0,
      "subject": "Hello {{record.data.name}}",
      "body": "Following up on your request."
    }
  ],
  "version": 1
}'
POST/api/outreach/campaigns/{id}/preview

Review eligible audience

Access: Owner, admin or member · Success: 200

Consent=true, valid email/international phone, unique addresses and no channel suppression. Returns latest version, SHA256 audience digest and up to 20 eligible contacts, plus skip reasons.

No request body is required.

Response

FieldTypeRequiredDetails
versionintegerNoPositive optimistic version returned by the latest read. Refresh on 409; do not overwrite stale changes. Min 1.
audienceTokenstringNoReviewed audience digest
totalintegerNoSource contacts
eligibleintegerNoEligible count
skippedobject[]No
contactsobject[]No
firstStepStepNo
Request shape (illustrative)
curl --request POST \
  --url 'https://app.drykraft.com/api/outreach/campaigns/00000000-0000-4000-8000-000000000001/preview' \
  --cookie 'drykraft_session=<YOUR_SESSION_TOKEN>'
POST/api/outreach/campaigns/{id}/launch

Launch reviewed audience

Access: Owner or admin · Success: 202

This performs real outreach asynchronously. Fresh digest/version/confirmation required. Verified enabled connector; validates QCall choices or approved WhatsApp body template parameters. Recheck stale audience on 409. Shared sample blocked.

JSON request

FieldTypeRequiredDetails
versionintegerYesPositive optimistic version returned by the latest read. Refresh on 409; do not overwrite stale changes. Min 1.
audienceTokenstringYes Pattern: ^[a-f0-9]{64}$.
confirmedtrueYes

Response

FieldTypeRequiredDetails
enrolledintegerNoEnrolled
skippedintegerNoSkipped
Request shape (illustrative)
curl --request POST \
  --url 'https://app.drykraft.com/api/outreach/campaigns/00000000-0000-4000-8000-000000000001/launch' \
  --cookie 'drykraft_session=<YOUR_SESSION_TOKEN>' \
  --header 'Content-Type: application/json' \
  --data '{
  "version": 1,
  "audienceToken": "<value>",
  "confirmed": true
}'
POST/api/outreach/campaigns/{id}/status

Pause, resume or cancel

Access: Owner or admin · Success: 200

Cannot change draft/cancelled. Pause waits before future steps; cancel stops unfinished executions. Already accepted provider side effects cannot be recalled.

JSON request

FieldTypeRequiredDetails
statusactive | paused | cancelledYesCampaign state

Response

FieldTypeRequiredDetails
statusstringNoNew state
Request shape (illustrative)
curl --request POST \
  --url 'https://app.drykraft.com/api/outreach/campaigns/00000000-0000-4000-8000-000000000001/status' \
  --cookie 'drykraft_session=<YOUR_SESSION_TOKEN>' \
  --header 'Content-Type: application/json' \
  --data '{
  "status": "active"
}'
POST/api/outreach/campaigns/{id}/contacts/{record}/stop

Stop one enrolled contact

Access: Owner, admin or member · Success: 200

Stops unfinished follow-ups for this campaign; does not permanently suppress other campaigns. Use Suppressions for that.

No request body is required.

Response

Use OK.

Request shape (illustrative)
curl --request POST \
  --url 'https://app.drykraft.com/api/outreach/campaigns/00000000-0000-4000-8000-000000000001/contacts/00000000-0000-4000-8000-000000000001/stop' \
  --cookie 'drykraft_session=<YOUR_SESSION_TOKEN>'
GET/api/outreach/activity

Read recent outreach activity

Access: Workspace member · Success: 200

Latest 100 deliveries and 50 incoming messages, with connection names. Unknown means acceptance was ambiguous: check provider before a new attempt.

No request body is required.

Response

FieldTypeRequiredDetails
deliveriesobject[]No
messagesobject[]No
Request shape (illustrative)
curl --request GET \
  --url 'https://app.drykraft.com/api/outreach/activity' \
  --cookie 'drykraft_session=<YOUR_SESSION_TOKEN>'
GET/api/outreach/suppressions

Read channel suppressions

Access: Workspace member · Success: 200

Latest 100. Permanent per workspace/channel; no removal API in current release.

No request body is required.

Response

object[]. channel, recipient, reason, created_at

Request shape (illustrative)
curl --request GET \
  --url 'https://app.drykraft.com/api/outreach/suppressions' \
  --cookie 'drykraft_session=<YOUR_SESSION_TOKEN>'
POST/api/outreach/suppressions

Suppress recipient

Access: Owner, admin or member · Success: 200

Normalizes email lowercase or international +phone; stops active sequences on this channel/workspace.

JSON request

FieldTypeRequiredDetails
channelemail | sms | voice | whatsappYesChannel
recipientstringYesEmail or international phone Max 200 characters.

Response

Use OK.

Request shape (illustrative)
curl --request POST \
  --url 'https://app.drykraft.com/api/outreach/suppressions' \
  --cookie 'drykraft_session=<YOUR_SESSION_TOKEN>' \
  --header 'Content-Type: application/json' \
  --data '{
  "channel": "email",
  "recipient": "<Email or international phone>"
}'