API Reference
Campaigns
Campaign Object

Campaign Object

Core CRUD and lifecycle operations on public campaign objects: create, list, get, update metadata, soft-delete, archive, and clone.

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

v1 campaign type. Public Campaigns v1 supports campaignType: "broadcast". journey is accepted by the schema only so the API can return a stable unsupported-type response instead of pretending the campaign does not exist.


Create Campaign

Creates a new broadcast campaign draft. You can seed audience, content, and schedule intent during creation, or configure them later through the dedicated binding endpoints.

POST /campaigns
Authorization: Bearer <token>
Content-Type: application/json
Idempotency-Key: <uuid-v4>   (optional, 24-hour deduplication)

Required scope: campaigns:create

Request body

FieldTypeRequiredDescription
campaignTypestringYesMust be "broadcast" in v1.
namestringYes1-255 characters.
channelstringYesemail, sms, push, or direct_mail.
descriptionstring | nullNoOptional description.
categorystring | nullNoClassification hint. Invalid or omitted values default to general.
tagsstring[]NoUp to 25 tags, max 100 chars each. Category is auto-added.
externalIdstring | nullNoYour system's identifier for this campaign.
metadataobject | nullNoArbitrary external-system metadata.
contentobject | nullNoOptional content seed. templateId may be omitted at create time.
audienceobject | nullNoOptional audience seed. If supplied, include must contain at least one entry.
scheduleobject | nullNoOptional schedule intent seed. If sendAt is supplied and mode is omitted, the API treats it as mode: "at".

content object

FieldTypeRequiredDescription
templateIdstring | nullNoID of a published template matching the campaign channel.
senderProfileIdstring | nullNoSender profile ID for channels that use sender profiles.
subjectLinestring | nullNoEmail subject line. Stored only as draft configuration until content is complete.

audience object

FieldTypeRequiredDescription
includearrayYes1-25 audience/segment entries.
excludearrayNo0-25 suppression entries.

Each audience entry has audienceId and type, where type is "audience" or "segment".

schedule object

The schedule seed is channel-dependent. For digital channels (email, sms, push):

FieldTypeRequiredDescription
modestringNo"now" or "at". Defaults to "at" when sendAt is present, otherwise "now".
sendAtstring | nullConditionalISO 8601 timestamp. Required when resolved mode is "at".
timezonestring | nullNoIANA timezone string. Defaults to "UTC".

For direct mail campaigns, use the batch-date model instead:

FieldTypeRequiredDescription
modestringYesMust be "batch_on_date".
batchDatestringYesTarget fulfillment date in YYYY-MM-DD format.
timezonestring | nullNoIANA timezone used to interpret the date.

The schedule object in all GET responses includes a kind discriminator ("digital_send" or "direct_mail_batch") and, for direct mail, a timezoneSource field indicating how the timezone was resolved. See Schedule & Send for full details.

Example request

curl -X POST https://api.experiture.ai/public/v1/campaigns \
  -H "Authorization: Bearer <your_access_token>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "campaignType": "broadcast",
    "name": "Spring Re-engagement Email",
    "channel": "email",
    "category": "retention",
    "tags": ["spring-2026", "re-engagement"],
    "externalId": "crm-campaign-8821"
  }'

Response - 201 Created

{
  "success": true,
  "data": {
    "campaignId": "4130bada-9264-465f-bc0c-a26bebcfcc81",
    "versionId": "11111111-1111-1111-1111-111111111111",
    "campaignType": "broadcast",
    "authoringStatus": "draft",
    "channel": "email",
    "links": {
      "self": "/public/v1/campaigns/4130bada-9264-465f-bc0c-a26bebcfcc81",
      "summary": "/public/v1/campaigns/4130bada-9264-465f-bc0c-a26bebcfcc81/summary"
    }
  }
}

Errors

CodeHTTPMeaning
JOURNEY_API.PUBLIC.CAMPAIGNS.TYPE_UNSUPPORTED409campaignType is not supported in v1.
JOURNEY_API.PUBLIC.CAMPAIGNS.INVALID_CHANNEL400channel value is not supported.
JOURNEY_API.PUBLIC.CAMPAIGNS.SCHEDULE.SEND_AT_REQUIRED400Schedule mode resolves to "at" but no sendAt was supplied.
JOURNEY_API.PUBLIC.CAMPAIGNS.CONTENT.TEMPLATE_NOT_FOUND404templateId does not exist in this tenant.
JOURNEY_API.PUBLIC.CAMPAIGNS.CONTENT.TEMPLATE_NOT_PUBLISHED409Template exists but is not published.
JOURNEY_API.PUBLIC.CAMPAIGNS.CONTENT.CHANNEL_MISMATCH409Template channel does not match campaign channel.
JOURNEY_API.AUTH.INSUFFICIENT_SCOPE403Token lacks campaigns:create.

List Campaigns

Returns a paginated list of supported broadcast campaigns in the tenant.

GET /campaigns
Authorization: Bearer <token>

Required scope: campaigns:read

Query parameters

ParameterTypeDefaultDescription
limitinteger20Results per page. Range 1-100.
offsetinteger0Number of records to skip.
sortBystringupdatedAtcreatedAt, name, or updatedAt.
sortDirectionstringdescasc or desc.
campaignTypestringbroadcastOnly broadcast is supported in v1. journey returns 409 TYPE_UNSUPPORTED.
statusstring-Filter by authoring status, such as draft, published, or archived.
channelstring-Filter by channel, such as email or direct_mail.
tagstring-Filter campaigns containing this tag.
searchstring-Case-insensitive search on name and description.
updatedAfterISO 8601-Return campaigns updated after this timestamp.
updatedBeforeISO 8601-Return campaigns updated before this timestamp.

Response - 200 OK

{
  "success": true,
  "data": [
    {
      "campaignId": "4130bada-9264-465f-bc0c-a26bebcfcc81",
      "name": "Spring Re-engagement Email",
      "campaignType": "broadcast",
      "channel": "email",
      "authoringStatus": "draft",
      "category": "retention",
      "tags": ["retention", "spring-2026", "re-engagement"],
      "createdAt": "2026-04-25T10:00:00.000Z",
      "updatedAt": "2026-04-25T10:30:00.000Z",
      "links": {
        "self": "/public/v1/campaigns/4130bada-9264-465f-bc0c-a26bebcfcc81",
        "summary": "/public/v1/campaigns/4130bada-9264-465f-bc0c-a26bebcfcc81/summary"
      }
    }
  ],
  "pagination": {
    "total": 42,
    "limit": 50,
    "offset": 0
  }
}

Get Campaign

Returns the full public campaign object. This uses the same public summary presenter plus object metadata such as versionId, description, externalId, and metadata.

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

Required scope: campaigns:read

Response - 200 OK

{
  "success": true,
  "data": {
    "campaignId": "4130bada-9264-465f-bc0c-a26bebcfcc81",
    "name": "Spring Re-engagement Email",
    "campaignType": "broadcast",
    "channel": "email",
    "authoringStatus": "draft",
    "createdAt": "2026-04-25T10:00:00.000Z",
    "updatedAt": "2026-04-25T10:30:00.000Z",
    "schedule": {
      "kind": "digital_send",
      "mode": "now",
      "sendAt": null,
      "timezone": "UTC",
      "scheduled": false
    },
    "audience": {
      "included": [
        { "id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name": null, "type": "audience", "memberCount": null }
      ],
      "excluded": [],
      "reach": {
        "status": "idle",
        "evaluatedCount": null,
        "evaluatedAt": null,
        "isStale": false
      }
    },
    "content": {
      "template": {
        "id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
        "name": "Published API Email",
        "status": "published",
        "channel": "email"
      },
      "proofStatus": "unavailable"
    },
    "preflight": {
      "status": "not_evaluated",
      "checks": []
    },
    "latestExecution": {
      "status": "not_scheduled",
      "lastExecutionAt": null,
      "counts": null
    },
    "versionId": "11111111-1111-1111-1111-111111111111",
    "description": null,
    "category": "retention",
    "tags": ["retention", "spring-2026"],
    "externalId": "crm-campaign-8821",
    "metadata": { "source": "crm" },
    "links": {
      "self": "/public/v1/campaigns/4130bada-9264-465f-bc0c-a26bebcfcc81",
      "summary": "/public/v1/campaigns/4130bada-9264-465f-bc0c-a26bebcfcc81/summary"
    }
  }
}

Errors

CodeHTTPMeaning
JOURNEY_API.PUBLIC.CAMPAIGNS.NOT_FOUND404No campaign with this ID in the token tenant.
JOURNEY_API.PUBLIC.CAMPAIGNS.SUMMARY_TYPE_UNSUPPORTED409Campaign exists but its type does not have a public object presenter yet.
JOURNEY_API.AUTH.INSUFFICIENT_SCOPE403Token lacks campaigns:read.

Update Campaign Metadata

Updates campaign metadata. It does not change audience, content, or schedule configuration.

PATCH /campaigns/:id
Authorization: Bearer <token>
Content-Type: application/json

Required scope: campaigns:update

All request fields are optional.

FieldTypeDescription
namestring1-255 characters.
descriptionstring | nullDescription.
categorystring | nullClassification hint.
tagsstring[]Replaces existing tags. Category is auto-added.
externalIdstring | nullExternal system ID. null clears it.
metadataobject | nullReplaces external metadata. null clears it.

Response - 200 OK - same shape as Get Campaign.


Delete Campaign

Soft-deletes a campaign. Returns no body.

DELETE /campaigns/:id
Authorization: Bearer <token>

Required scope: campaigns:delete

Response - 204 No Content


Archive Campaign

Moves a campaign to archived status. The record remains visible when listing with status=archived.

POST /campaigns/:id/archive
Authorization: Bearer <token>
Content-Type: application/json

Required scope: campaigns:delete

Response - 200 OK - same shape as Get Campaign with authoringStatus: "archived".


Clone Campaign

Creates a new draft broadcast campaign as a copy of an existing broadcast.

POST /campaigns/:id/clone
Authorization: Bearer <token>
Content-Type: application/json
Idempotency-Key: <uuid-v4>   (optional, 24-hour deduplication)

Required scope: campaigns:create

FieldTypeDefaultDescription
namestring | null"{source} (Copy)"Name for the clone.
includeAudiencebooleantrueCopy audience bindings.
includeContentbooleantrueCopy content binding.
includeSchedulebooleanfalseCopy schedule intent.
externalIdstring | null-External ID for the clone.
metadataobject | null-External metadata for the clone.

Response - 201 Created - same shape as Get Campaign for the new clone.

Common errors

CodeHTTPMeaning
JOURNEY_API.PUBLIC.CAMPAIGNS.NOT_FOUND404Campaign not found.
JOURNEY_API.PUBLIC.CAMPAIGNS.TYPE_UNSUPPORTED409Source campaign is not a broadcast.
JOURNEY_API.PUBLIC.CAMPAIGNS.SUMMARY_UNAVAILABLE409Source campaign is missing persisted broadcast state.
JOURNEY_API.AUTH.INSUFFICIENT_SCOPE403Token lacks the required scope.

See Also