API reference

Workflow campaigns

Run a published workflow version for a list of contacts; pause, resume or abort it and follow its progress.

A workflow campaign runs a single published version of a workflow for each contact you upload; later edits to the workflow do not change it. Contacts are uploaded as entries; when the campaign starts, each valid entry becomes a workflow execution. A campaign can be paused, resumed or aborted, and its counts and node-by-node funnel can be read at any time. See Campaigns and workflows.

All routes need Authorization: Bearer <key>. Reading needs the viewer role; everything else needs member. Errors use the workflow error body {"detail": {"code": "...", "message": "..."}} described in Workflows. An unknown id answers 404 with code not_found and message Campaign not found.

OperationMethod and path
Create a campaignPOST /workflow-campaigns
List campaignsGET /workflow-campaigns
Get a campaignGET /workflow-campaigns/{campaign_id}
Delete a campaignDELETE /workflow-campaigns/{campaign_id}
Upload entriesPOST /workflow-campaigns/{campaign_id}/entries
List entriesGET /workflow-campaigns/{campaign_id}/entries
Download the entries templateGET /workflow-campaigns/{campaign_id}/entries/template
Start a campaignPOST /workflow-campaigns/{campaign_id}:start
Pause a campaignPOST /workflow-campaigns/{campaign_id}:pause
Resume a campaignPOST /workflow-campaigns/{campaign_id}:resume
Abort a campaignPOST /workflow-campaigns/{campaign_id}:abort
List a campaign's executionsGET /workflow-campaigns/{campaign_id}/executions
Get the campaign reportGET /workflow-campaigns/{campaign_id}/report

Lifecycle

Campaign statuses, in order:

  • draft: created; entries can be uploaded.
  • scheduled: started, waiting for its scheduled_at or for the worker to pick it up.
  • running: entries are being turned into executions.
  • paused: no execution takes its next step until you resume. When the wallet runs out, the platform pauses the campaign itself and sets paused_reason to balance-low.
  • completed: no entry is pending and every execution has finished.
  • aborted: stopped for good.

Campaigns have a kind. Those you create are batch. The platform also keeps one api campaign per workflow version to group single runs made with Run a workflow for one contact; api campaigns cannot be started or given entries.

The action routes put the verb after a colon, as in /workflow-campaigns/{campaign_id}:start. They take no body.

Operations

Create a campaign

POST /workflow-campaigns

Creates a campaign in draft, locked to a single published workflow version.

Auth: API key or session token. Role: member and up.

This route accepts an Idempotency-Key header; see Idempotency.

ParameterInTypeRequiredDescription
workflow_idbodystring (UUID)yesThe workflow.
namebodystringyes1 to 120 characters.
versionbodyintegernoThe published version to pin. Default: the latest.
bindingbodyobjectnoagent_overrides and number_overrides, each an object keyed by agent node id.
scheduled_atbodystringnoISO 8601 timestamp with an offset. After you start the campaign, it waits until this time.

Request

bash
curl -X POST https://api.sevennadi.si/workflow-campaigns \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"workflow_id": "2ab95da4-50dd-4492-a355-793ec7d810c5", "name": "October follow-ups"}'

Response 201 Created

json
{
  "id": "7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9",
  "name": "October follow-ups",
  "workflow_id": "2ab95da4-50dd-4492-a355-793ec7d810c5",
  "workflow_version": 1,
  "kind": "batch",
  "status": "draft",
  "entries_count": 0,
  "success_count": 0,
  "failure_count": 0,
  "neutral_count": 0,
  "terminal_count": 0,
  "created_at": "2026-10-13T08:30:00Z",
  "updated_at": "2026-10-13T08:30:00Z"
}

scheduled_at and paused_reason appear only when set.

Errors

StatusCodeMessage
404not_foundWorkflow not found
422validation_failedworkflow_id is required
422validation_failedname must be 1 to 120 characters
422validation_failedUnknown field <name>
422validation_failedversion must be an integer or null or Version <n> is not published
422validation_failedbinding holds agent_overrides and number_overrides
422validation_failedscheduled_at must be a timezone-aware ISO timestamp
422no_published_versionThe workflow has no published version to pin

List campaigns

GET /workflow-campaigns

Returns the account's campaigns with their counts.

Auth: API key or session token. Role: viewer and up.

ParameterInTypeRequiredDescription
workflow_idquerystring (UUID)noOnly campaigns of this workflow.
statusquerystringnodraft, scheduled, running, paused, completed or aborted.
kindquerystringnobatch or api.
sort_byquerystringnocreated_at (default), updated_at, name, entries_count, success_count or failure_count.
orderquerystringnoasc or desc (default).
limitqueryintegerno1 to 100. Default 20.
offsetqueryintegernoRows to skip. Default 0.

Request

bash
curl "https://api.sevennadi.si/workflow-campaigns?status=running&sort_by=updated_at" \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{
  "items": [
    {
      "id": "7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9",
      "name": "October follow-ups",
      "workflow_id": "2ab95da4-50dd-4492-a355-793ec7d810c5",
      "workflow_version": 1,
      "kind": "batch",
      "status": "running",
      "entries_count": 18,
      "success_count": 12,
      "failure_count": 3,
      "neutral_count": 0,
      "terminal_count": 15,
      "created_at": "2026-10-13T08:30:00Z",
      "updated_at": "2026-10-13T09:10:00Z"
    }
  ],
  "total": 1,
  "limit": 20,
  "offset": 0
}

Errors

StatusCodeMessage
422validation_failedFor example limit: Input should be less than or equal to 100

Get a campaign

GET /workflow-campaigns/{campaign_id}

Returns one campaign with its entries counted by status and its validation failures counted by code.

Auth: API key or session token. Role: viewer and up.

ParameterInTypeRequiredDescription
campaign_idpathstring (UUID)yesThe campaign.

Request

bash
curl https://api.sevennadi.si/workflow-campaigns/7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9 \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{
  "campaign": {
    "id": "7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9",
    "name": "October follow-ups",
    "workflow_id": "2ab95da4-50dd-4492-a355-793ec7d810c5",
    "workflow_version": 1,
    "kind": "batch",
    "status": "draft",
    "entries_count": 18,
    "success_count": 0,
    "failure_count": 0,
    "neutral_count": 0,
    "terminal_count": 0,
    "created_at": "2026-10-13T08:30:00Z",
    "updated_at": "2026-10-13T08:35:00Z"
  },
  "entry_counts": {"pending": 18, "failed_validation": 2},
  "validation_errors": {"invalid_phone": 2}
}

entries_count leaves out entries that failed validation.

Errors

StatusCodeMessage
404not_foundCampaign not found

Delete a campaign

DELETE /workflow-campaigns/{campaign_id}

Deletes a campaign. Only a draft campaign with no entries and no executions can be deleted.

Auth: API key or session token. Role: member and up.

ParameterInTypeRequiredDescription
campaign_idpathstring (UUID)yesThe campaign.

Request

bash
curl -X DELETE https://api.sevennadi.si/workflow-campaigns/7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9 \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 204 No Content

No body.

Errors

StatusCodeMessage
404not_foundCampaign not found
409invalid_stateOnly a draft campaign with no entries and no executions can be deleted (with campaign_status)

Upload entries

POST /workflow-campaigns/{campaign_id}/entries

Adds contacts to a campaign. Send a CSV file as the raw request body with Content-Type: text/csv, or a JSON array of objects with Content-Type: application/json. This is not a multipart upload.

Each row is checked against the fields of the pinned workflow version. Valid rows become pending entries. Invalid rows are kept as failed_validation entries so you can see them; uploading a corrected row with the same reference_id replaces the failed one. You may upload while the campaign is draft, scheduled or running. In a running campaign, new entries are dispatched at once.

  • A CSV needs a header row that names each column once, and must contain every required field as a column.
  • A column or key that the workflow does not know is refused for the whole upload.
  • A row without reference_id gets one derived from its values, so an identical row uploaded twice is ignored.
  • Each upload: up to 150,000 rows, and 32 MB at most.

Auth: API key or session token. Role: member and up.

ParameterInTypeRequiredDescription
campaign_idpathstring (UUID)yesThe campaign.
Content-Typeheaderstringyestext/csv or application/json.
bodybodyCSV text or JSON arrayyesThe contacts.

Request

bash
curl -X POST https://api.sevennadi.si/workflow-campaigns/7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9/entries \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: text/csv" \
  --data-binary @contacts.csv

Response 200 OK

json
{
  "accepted": 18,
  "corrected": 0,
  "failed": 2,
  "entries_count": 18,
  "failures": [
    {"row": 7, "reference_id": "loan-1048", "code": "invalid_phone", "message": "mobile_number: expected an E.164 phone number, e.g. +919876543210"},
    {"row": 12, "reference_id": "loan-1042", "code": "duplicate_reference_id", "message": "reference_id loan-1042 is already in this campaign"}
  ],
  "warnings": []
}

For CSV, row counts the header as row 1. failures and warnings list at most 1000 items each. A warning with code missing_default_recipient marks an accepted row that has no mobile_number although the workflow dials it.

Errors

StatusCodeMessage
404not_foundCampaign not found
409invalid_stateEntries can only be added while the campaign is draft, scheduled or running
413payload_too_largeUploads are capped at 32 MB or Uploads are capped at 150,000 rows
422validation_failedSend text/csv or application/json
422validation_failedThe CSV must be UTF-8, The CSV is empty, The CSV header must name each column once, Malformed CSV: <detail>
422validation_failedThe body is not valid JSON or The body must be a JSON array of entry objects
422unknown_fieldUnknown field <name> (with fields)
422missing_required_fieldMissing required column <name> (with fields)

List entries

GET /workflow-campaigns/{campaign_id}/entries

Returns a campaign's entries.

Auth: API key or session token. Role: viewer and up.

ParameterInTypeRequiredDescription
campaign_idpathstring (UUID)yesThe campaign.
statusquerystringnopending, failed_validation, dispatched or completed.
sort_byquerystringnocreated_at (default), reference_id or status.
orderquerystringnoasc or desc (default).
limitqueryintegerno1 to 100. Default 20.
offsetqueryintegernoRows to skip. Default 0.

Request

bash
curl "https://api.sevennadi.si/workflow-campaigns/7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9/entries?status=failed_validation" \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{
  "items": [
    {
      "id": "e1f2a3b4-c5d6-4e7f-8091-a2b3c4d5e6f7",
      "reference_id": "loan-1048",
      "mobile_number": "98765",
      "name": "Ravi",
      "custom_fields": {"due_date": "2026-11-04"},
      "status": "failed_validation",
      "validation_error": "invalid_phone",
      "created_at": "2026-10-13T08:35:00Z"
    }
  ],
  "total": 1,
  "limit": 20,
  "offset": 0
}

A dispatched entry carries the execution_id of its execution. An entry can also have the status skipped: it was held back at dispatch by the do-not-call list, missing consent or the daily frequency cap, and validation_error holds the reason. The status filter does not accept skipped; list without a filter to see those entries.

Errors

StatusCodeMessage
404not_foundCampaign not found
422validation_failedA message naming the bad query parameter

Download the entries template

GET /workflow-campaigns/{campaign_id}/entries/template

Returns a CSV header row for the campaign's workflow version: the fields the start node declares, or the four system fields if it declares none.

Auth: API key or session token. Role: viewer and up.

ParameterInTypeRequiredDescription
campaign_idpathstring (UUID)yesThe campaign.

Request

bash
curl -o template.csv https://api.sevennadi.si/workflow-campaigns/7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9/entries/template \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK with Content-Type: text/csv

text
reference_id,mobile_number,name,email

Errors

StatusCodeMessage
404not_foundCampaign not found

Start a campaign

POST /workflow-campaigns/{campaign_id}:start

Starts a draft campaign. It becomes scheduled, then running as soon as the worker picks it up, or at scheduled_at if that is in the future. Starting a campaign that is already scheduled succeeds and changes nothing.

Auth: API key or session token. Role: member and up. When the operator sets REQUIRE_VERIFIED_EMAIL, the login must have a verified email address.

This route accepts an Idempotency-Key header.

Warning: Starting a campaign places real calls when the platform is connected to live telephony.

ParameterInTypeRequiredDescription
campaign_idpathstring (UUID)yesThe campaign.

Request

bash
curl -X POST "https://api.sevennadi.si/workflow-campaigns/7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9:start" \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{"status": "scheduled"}

Errors

StatusCodeMessage
404not_foundCampaign not found
409invalid_stateOnly batch campaigns are started
409invalid_stateThe campaign already started (status <status>)
409invalid_stateThe campaign has no pending entries

Every invalid_state error also carries campaign_status.

Pause a campaign

POST /workflow-campaigns/{campaign_id}:pause

Pauses a scheduled or running campaign. Calls already in progress finish; executions do not take their next step until you resume.

Auth: API key or session token. Role: member and up.

ParameterInTypeRequiredDescription
campaign_idpathstring (UUID)yesThe campaign.

Request

bash
curl -X POST "https://api.sevennadi.si/workflow-campaigns/7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9:pause" \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{"status": "paused"}

Errors

StatusCodeMessage
404not_foundCampaign not found
409invalid_stateOnly a scheduled or running campaign can be paused

Resume a campaign

POST /workflow-campaigns/{campaign_id}:resume

Resumes a paused campaign. A campaign that had not started yet goes back to scheduled; otherwise it returns to running, entries uploaded during the pause are dispatched and held executions continue.

Auth: API key or session token. Role: member and up. When the operator sets REQUIRE_VERIFIED_EMAIL, the login must have a verified email address.

This route accepts an Idempotency-Key header.

ParameterInTypeRequiredDescription
campaign_idpathstring (UUID)yesThe campaign.

Request

bash
curl -X POST "https://api.sevennadi.si/workflow-campaigns/7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9:resume" \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{"status": "running"}

status is the campaign's status after the resume: running, scheduled, or completed if nothing was left to do.

Errors

StatusCodeMessage
404not_foundCampaign not found
409invalid_stateOnly a paused campaign can be resumed

Abort a campaign

POST /workflow-campaigns/{campaign_id}:abort

Stops a campaign for good. Executions that are under way end with the status aborted before their next external action, and send their webhook. Executions that had not begun end without a webhook. Entries that were never dispatched stay pending. An aborted campaign cannot be resumed.

Auth: API key or session token. Role: member and up.

ParameterInTypeRequiredDescription
campaign_idpathstring (UUID)yesThe campaign.

Request

bash
curl -X POST "https://api.sevennadi.si/workflow-campaigns/7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9:abort" \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{"status": "aborted"}

Errors

StatusCodeMessage
404not_foundCampaign not found
409invalid_stateThe campaign is already completed or The campaign is already aborted

List a campaign's executions

GET /workflow-campaigns/{campaign_id}/executions

Returns the executions of a campaign in summary form.

Auth: API key or session token. Role: viewer and up.

ParameterInTypeRequiredDescription
campaign_idpathstring (UUID)yesThe campaign.
statusquerystringnopending, running, completed, failed, cancelled or aborted.
outcomequerystringnosuccess, failure, neutral, or none for executions without an outcome.
sort_byquerystringnocreated_at (default), updated_at, status or outcome.
orderquerystringnoasc or desc (default).
limitqueryintegerno1 to 100. Default 20.
offsetqueryintegernoRows to skip. Default 0.

Request

bash
curl "https://api.sevennadi.si/workflow-campaigns/7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9/executions?outcome=failure" \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{
  "items": [
    {
      "id": "exec:7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9:loan-1044",
      "campaign_id": "7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9",
      "status": "completed",
      "current_node_id": "n_end_unreachable",
      "termination_reason": "unreachable",
      "outcome": "failure",
      "call_count": 3,
      "created_at": "2026-10-13T09:00:00Z",
      "updated_at": "2026-10-13T12:40:00Z"
    }
  ],
  "total": 1,
  "limit": 20,
  "offset": 0
}

Errors

StatusCodeMessage
404not_foundCampaign not found
422validation_failedA message naming the bad query parameter

Get the campaign report

GET /workflow-campaigns/{campaign_id}/report

Returns totals for a campaign: executions by status, executions by termination reason, and a funnel that counts how often each node ended in each status.

Auth: API key or session token. Role: viewer and up.

ParameterInTypeRequiredDescription
campaign_idpathstring (UUID)yesThe campaign.

Request

bash
curl https://api.sevennadi.si/workflow-campaigns/7d6c5b4a-3928-4170-8695-a4b3c2d1e0f9/report \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{
  "executions": {"completed": 15, "running": 3},
  "termination_reasons": {"reached": 12, "unreachable": 3},
  "funnel": [
    {"node_id": "n_start", "status": "completed", "count": 18},
    {"node_id": "n_call", "status": "completed", "count": 21},
    {"node_id": "n_retry", "status": "completed", "count": 6},
    {"node_id": "n_end_reached", "status": "completed", "count": 12},
    {"node_id": "n_end_unreachable", "status": "completed", "count": 3}
  ]
}

The funnel follows the order of the nodes in the definition. A node that ran several times for one contact, such as a retried call, is counted once per attempt.

Errors

StatusCodeMessage
404not_foundCampaign not found