API Reference
Campaigns
Schedule & Send

Schedule & Send

Set schedule intent, then create an execution job for a future send or an immediate send.

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


Set Schedule Intent

Stores when a draft campaign should send. This does not publish, schedule, or send the campaign.

The request body is channel-dependent: direct_mail campaigns use a batch-date scheduling model; all other channels (email, SMS, push) use a timestamp model.

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

Required scope: campaigns:update

⚠️

Schedule intent can only be updated while the campaign is in draft status.

Digital channels (email, sms, push)

FieldTypeRequiredDescription
modestringYes"now" or "at".
sendAtstring | nullConditionalISO 8601 timestamp. Required when mode is "at".
timezonestring | nullNoIANA timezone string. Defaults to "UTC".

Example — email, future send

curl -X PUT https://api.experiture.ai/public/v1/campaigns/4130bada-9264-465f-bc0c-a26bebcfcc81/schedule \
  -H "Authorization: Bearer <your_access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "at",
    "sendAt": "2026-05-01T09:00:00.000Z",
    "timezone": "America/New_York"
  }'

Direct mail

Direct mail uses a date-only schedule — the channel's fulfillment pipeline does not accept an intraday time.

FieldTypeRequiredDescription
modestringYesMust be "batch_on_date".
batchDatestringYesTarget fulfillment date in YYYY-MM-DD format.
timezonestring | nullNoIANA timezone used to interpret the date. Defaults to tenant default, then "UTC".

Example — direct mail

curl -X PUT https://api.experiture.ai/public/v1/campaigns/4130bada-9264-465f-bc0c-a26bebcfcc81/schedule \
  -H "Authorization: Bearer <your_access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "batch_on_date",
    "batchDate": "2026-05-01",
    "timezone": "America/New_York"
  }'

Response — 200 OK — same shape as Get Campaign. The schedule object in the response includes a kind discriminator: "digital_send" for digital channels or "direct_mail_batch" for direct mail. See Schedule object variants below.

Errors

CodeHTTPMeaning
JOURNEY_API.PUBLIC.CAMPAIGNS.NOT_FOUND404Campaign not found.
JOURNEY_API.PUBLIC.CAMPAIGNS.NOT_DRAFT409Campaign is not a draft.
JOURNEY_API.SCHEDULE.SEND_AT_REQUIRED400mode is "at" but sendAt is missing.
JOURNEY_API.SCHEDULE.SEND_AT_INVALID400sendAt is present but malformed or in the past.
JOURNEY_API.SCHEDULE.BATCH_DATE_REQUIRED400mode is "batch_on_date" but batchDate is missing.
JOURNEY_API.SCHEDULE.BATCH_DATE_INVALID400batchDate is present but malformed or in the past.
JOURNEY_API.SCHEDULE.UNSUPPORTED_CHANNEL400Channel is not supported for the requested schedule mode.
JOURNEY_API.AUTH.INSUFFICIENT_SCOPE403Token lacks campaigns:update.

Schedule Object Variants

The schedule object in campaign responses uses a kind discriminator to indicate which scheduling model applies.

Digital channels

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

Direct mail

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

timezoneSource indicates how the timezone was resolved:

ValueMeaning
"request"Timezone was explicitly supplied in the request.
"tenant_default"Timezone was not supplied; tenant default was applied.
"utc_fallback"No request timezone and no tenant default; UTC was used.

Create Schedule Job

Commits a draft campaign to a future execution. For digital campaigns, if sendAt is omitted the API uses the saved schedule intent. For direct mail campaigns, use batchDate.

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

Required scope: campaigns:schedule

⚠️

The campaign must be a draft with at least one included audience and a published template bound before a schedule job can be created.

Request body

FieldTypeRequiredDescription
sendAtstring | nullNoISO 8601 timestamp for digital channels. If omitted, uses saved schedule intent. Not used for direct mail.
batchDatestring | nullNoYYYY-MM-DD fulfillment date for direct mail. If omitted, uses saved schedule intent. Not used for digital channels.
timezonestring | nullNoIANA timezone string. Defaults to saved schedule timezone or "UTC".
dryRunbooleanNoIf true, validates and returns 200 without committing execution artifacts.

Dry-run response — 200 OK

{
  "success": true,
  "data": {
    "journeyId": "4130bada-9264-465f-bc0c-a26bebcfcc81",
    "versionId": "11111111-1111-1111-1111-111111111111",
    "status": "published",
    "dryRun": true,
    "warnings": [],
    "bindings": [
      {
        "journey_version_id": "11111111-1111-1111-1111-111111111111",
        "node_key": "send_1",
        "manifest_id": "33333333-3333-3333-3333-333333333333",
        "placeholder_manifest_id": null,
        "touchpoint_id": 123,
        "channel": "email"
      }
    ]
  }
}

Committed response — 201 Created (digital)

{
  "success": true,
  "data": {
    "journeyId": "4130bada-9264-465f-bc0c-a26bebcfcc81",
    "versionId": "11111111-1111-1111-1111-111111111111",
    "status": "published",
    "warnings": [],
    "bindings": [
      {
        "journey_version_id": "11111111-1111-1111-1111-111111111111",
        "node_key": "send_1",
        "manifest_id": "33333333-3333-3333-3333-333333333333",
        "placeholder_manifest_id": null,
        "touchpoint_id": 123,
        "channel": "email"
      }
    ],
    "manifestId": "33333333-3333-3333-3333-333333333333",
    "scheduleId": "44444444-4444-4444-4444-444444444444",
    "touchpointId": 123,
    "sendAt": "2026-05-01T09:00:00.000Z",
    "timezone": "America/New_York"
  }
}

Committed response — 201 Created (direct mail)

{
  "success": true,
  "data": {
    "journeyId": "4130bada-9264-465f-bc0c-a26bebcfcc81",
    "versionId": "11111111-1111-1111-1111-111111111111",
    "status": "published",
    "warnings": [],
    "bindings": [
      {
        "journey_version_id": "11111111-1111-1111-1111-111111111111",
        "node_key": "send_1",
        "manifest_id": "33333333-3333-3333-3333-333333333333",
        "placeholder_manifest_id": null,
        "touchpoint_id": 123,
        "channel": "direct_mail"
      }
    ],
    "manifestId": "33333333-3333-3333-3333-333333333333",
    "scheduleId": "44444444-4444-4444-4444-444444444444",
    "touchpointId": 123,
    "batchDate": "2026-05-01",
    "timezone": "America/New_York"
  }
}

Create Send Job

Commits a draft campaign to immediate execution.

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

Required scope: campaigns:send

🚫

Not supported for direct mail. This endpoint returns 400 JOURNEY_API.SCHEDULE.INVALID_FOR_CHANNEL when the campaign channel is direct_mail. Direct mail requires a fulfillment date and cannot be triggered as an immediate send. Use POST /schedule-jobs with a batchDate instead.

Request body

FieldTypeRequiredDescription
dryRunbooleanNoIf true, validates and returns 200 without committing execution artifacts.

Response — 201 Created for committed sends, 200 OK for dry runs. Same shape as Create Schedule Job.


Execution Errors

CodeHTTPMeaning
JOURNEY_API.PUBLIC.CAMPAIGNS.NOT_FOUND404Campaign not found.
JOURNEY_API.PUBLIC.CAMPAIGNS.TYPE_UNSUPPORTED409Only broadcast campaigns can be scheduled or sent in v1.
JOURNEY_API.PUBLIC.CAMPAIGNS.NOT_DRAFT409Campaign is not a draft.
JOURNEY_API.PUBLIC.CAMPAIGNS.CONTENT.REQUIRED409Published template/content is not configured.
JOURNEY_API.PUBLIC.CAMPAIGNS.AUDIENCE.REQUIRED409At least one included audience is required.
JOURNEY_API.PUBLIC.CAMPAIGNS.VERSION_MISSING409Campaign has no current version.
JOURNEY_API.SCHEDULE.SEND_AT_REQUIRED400Future schedule execution has no send time.
JOURNEY_API.SCHEDULE.SEND_AT_INVALID400sendAt is malformed or in the past.
JOURNEY_API.SCHEDULE.BATCH_DATE_REQUIRED400Direct mail schedule has no batch date.
JOURNEY_API.SCHEDULE.BATCH_DATE_INVALID400batchDate is malformed or in the past.
JOURNEY_API.SCHEDULE.INVALID_FOR_CHANNEL400Operation is not permitted for this campaign's channel (e.g. immediate send on direct mail).
JOURNEY_API.SCHEDULE.UNSUPPORTED_CHANNEL400Channel is not supported for the requested schedule mode.
JOURNEY_API.SCHEDULE.UNSUPPORTED_TYPE500Internal: unsupported schedule type encountered. Contact support if this persists.
JOURNEY_API.BROADCASTS.SCHEDULE.PREFLIGHT_BLOCKERS400Preflight found blocking issues.
JOURNEY_API.AUTH.INSUFFICIENT_SCOPE403Token lacks the required scope.

Schedule vs Send

POST /schedule-jobsPOST /send-jobs
Scopecampaigns:schedulecampaigns:send
TimingFuture sendAt (digital) or batchDate (direct mail)Immediate
Channels supportedAll (email, sms, push, direct_mail)Digital only (email, sms, push)
Uses saved schedule intentYes, when sendAt/batchDate is omittedNo
dryRun supportedYesYes
IdempotencyYesYes

See Also