API Reference
Campaigns
Status & Metrics

Status & Metrics

Observe campaign setup, execution state, and execution counts.

Base URL: https://api.experiture.ai/public/v1


Get Campaign Summary

Returns a redacted setup summary for a broadcast campaign. The summary is safe for third-party systems: it does not include internal wizard state, sample contact records, private execution metadata, or caller-supplied tenant headers.

GET /campaigns/:id/summary
Authorization: Bearer <token>

Required scope: campaigns:read

Response - 200 OK

{
  "success": true,
  "data": {
    "campaignId": "4130bada-9264-465f-bc0c-a26bebcfcc81",
    "name": "Spring Re-engagement Direct Mail",
    "campaignType": "broadcast",
    "channel": "direct_mail",
    "authoringStatus": "draft",
    "createdAt": "2026-04-25T10:00:00.000Z",
    "updatedAt": "2026-04-25T10:30:00.000Z",
    "schedule": {
      "kind": "digital_send",
      "mode": "at",
      "sendAt": "2026-05-01T09:00:00.000Z",
      "timezone": "America/New_York",
      "scheduled": true
    },
    "audience": {
      "included": [
        { "id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name": null, "type": "segment", "memberCount": null }
      ],
      "excluded": [],
      "reach": {
        "status": "ok",
        "evaluatedCount": 18432,
        "evaluatedAt": "2026-04-25T10:20:00.000Z",
        "isStale": false
      }
    },
    "content": {
      "template": {
        "id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
        "name": "Spring DM v3",
        "status": "published",
        "channel": "direct_mail"
      },
      "proofStatus": "unavailable"
    },
    "preflight": {
      "status": "not_evaluated",
      "checks": []
    },
    "latestExecution": {
      "status": "not_scheduled",
      "lastExecutionAt": null,
      "counts": null
    },
    "links": {
      "self": "/public/v1/campaigns/4130bada-9264-465f-bc0c-a26bebcfcc81/summary"
    }
  }
}

audience.reach.status values

StatusMeaning
idleNo reach evaluation has run since this audience was bound.
pendingEvaluation is queued or in progress — evaluatedCount is not yet reliable.
okEvaluation completed successfully. evaluatedCount and evaluatedAt reflect the current state.
failedEvaluation failed. evaluatedCount reflects the prior successful run if available. Retry after a short delay or rebind the audience to trigger a fresh evaluation.

schedule object variants

The schedule object uses a kind discriminator based on channel. For digital channels (email, SMS, push):

{
  "kind": "digital_send",
  "mode": "at",
  "sendAt": "2026-05-01T09:00:00.000Z",
  "timezone": "America/New_York",
  "scheduled": true
}

For direct mail campaigns:

{
  "kind": "direct_mail_batch",
  "mode": "batch_on_date",
  "batchDate": "2026-05-01",
  "timezone": "America/New_York",
  "timezoneSource": "request",
  "scheduled": true
}

timezoneSource is one of "request" (caller-supplied), "tenant_default" (tenant fallback), or "utc_fallback" (no timezone configured).

isStale is true when the audience definition changed after the last evaluation — counts may not reflect current segment membership.

⚠️

If the campaign exists but is not a supported public v1 type, the API returns 409 SUMMARY_TYPE_UNSUPPORTED, not 404.


Get Campaign Status

Returns schedule details and the latest execution run for a broadcast campaign.

GET /campaigns/:id/status
Authorization: Bearer <token>

Required scope: campaigns:read

Response - 200 OK

{
  "success": true,
  "data": {
    "campaignId": "4130bada-9264-465f-bc0c-a26bebcfcc81",
    "name": "Spring Re-engagement Direct Mail",
    "authoringStatus": "published",
    "schedule": {
      "scheduleId": "44444444-4444-4444-4444-444444444444",
      "sendAt": "2026-05-01T09:00:00.000Z",
      "timezone": "America/New_York",
      "active": true
    },
    "execution": {
      "state": "completed",
      "touchpointId": 123,
      "manifestId": "33333333-3333-3333-3333-333333333333",
      "channel": "direct_mail",
      "lastExecution": {
        "executionId": "55555555-5555-5555-5555-555555555555",
        "startedAt": "2026-05-01T09:00:05.000Z",
        "completedAt": "2026-05-01T09:47:22.000Z",
        "status": "completed",
        "counts": {
          "scheduled": 17491,
          "hydrated": 17491,
          "composed": 17485,
          "injected": 17485,
          "sent": 17480,
          "failed": 5
        }
      }
    }
  }
}

If the campaign has not been scheduled, the response omits schedule and returns execution.state: "not_scheduled".

execution.state values

StateMeaning
not_scheduledCampaign has no execution history and no schedule.
scheduledCampaign has a future scheduled send.
pending_or_overdueScheduled send time has passed but no execution has started.
runningLatest execution is running.
completedLatest execution completed.
failedLatest execution failed.

Finalization tracking. When a POST /schedule-jobs or POST /send-jobs request returns 202 Accepted with status: "finalizing", the execution binding is being created asynchronously by the broadcast finalization worker. While the worker is in flight, this endpoint may return execution.state: "not_scheduled" (no schedule bound yet) or "scheduled" (after binding completes). The polling cadence depends on volume and preflight depth — typically seconds, but production-grade direct-mail finalization can take longer when execution artifacts are being prepared. Re-issuing the schedule-job request while a finalization is in flight is safe — the API returns the existing jobId rather than enqueuing a duplicate.


Get Campaign Metrics

Returns pipeline counts for the latest execution. Campaigns with no execution return zero counts.

GET /campaigns/:id/metrics
Authorization: Bearer <token>

Required scope: analytics:read

Metrics intentionally use analytics:read, not campaigns:read.

Response - 200 OK

{
  "success": true,
  "data": {
    "campaignId": "4130bada-9264-465f-bc0c-a26bebcfcc81",
    "counts": {
      "scheduled": 17491,
      "hydrated": 17491,
      "composed": 17485,
      "injected": 17485,
      "sent": 17480,
      "failed": 5
    }
  }
}

Common errors

CodeHTTPMeaning
JOURNEY_API.PUBLIC.CAMPAIGNS.NOT_FOUND404Campaign not found.
JOURNEY_API.PUBLIC.CAMPAIGNS.TYPE_UNSUPPORTED409Campaign type is not supported for this public operation yet.
JOURNEY_API.PUBLIC.CAMPAIGNS.STATUS_INCONSISTENT500Status cannot be assembled because execution metadata is inconsistent.
JOURNEY_API.AUTH.INSUFFICIENT_SCOPE403Token lacks the required scope.

Choosing Between Status and Metrics

/status/metrics
Scopecampaigns:readanalytics:read
Execution stateYesNo
Schedule detailsYesNo
Pipeline countsLatest runLatest run counts only
Use caseOperational monitoringBI and reporting

See Also