Loyalty

Cancel a scheduled campaign

Cancel a scheduled campaign before its delayed job fires, removing the trigger and returning the campaign to draft (its sendAt is cleared). Allowed only when the campaign is scheduled; a draft, sending, sent or finished campaign is rejected. Synchronous: returns 200 with the campaign already back in draft.

post/v1/loyalty/campaigns/{id}/cancel

Request

  • Base URL: https://api.prod.keyban.io
  • URL: https://api.prod.keyban.io/v1/loyalty/campaigns/{id}/cancel
  • Auth: API key in header X-Api-Key

Path parameters

idstring uuid required

Campaign ID

Response

Campaign schedule cancelled, back to draft

idstring uuid required

Entity UUID

createdAtstring date-time required

Creation date (ISO 8601)

updatedAtstring date-time required

Last update date (ISO 8601)

applicationstring uuid required

Application (brand) the campaign belongs to.

namestring required

Campaign name shown in the back-office campaign list.

descriptionstring nullable

Internal note describing the campaign intent. Never sent to customers.

channelsstring[] required

Wallet channels the campaign targets — a non-empty subset of google/apple.

sendAtstring date-time nullable

Scheduled send time (RFC 3339). Null means immediate send when triggered.

status'draft' | 'scheduled' | 'sending' | 'sent' | 'finished' required

Lifecycle status. Server-managed: a campaign is always created as draft.

audienceSnapshotCountinteger nullable

Audience size frozen when sending starts: the count of opted-in accounts matching the targeting, BEFORE the per-recipient consent and frequency-cap exclusions. It can therefore be higher than the number of actual deliveries. Null until the campaign starts sending.

conversionWindowDaysinteger required

Days after sending during which conversions are measured. Defaults to 7.

sentAtstring date-time nullable

Timestamp when sending started (anchors the conversion window). Null until sent.

isStrandedboolean

Computed flag, set only on the campaign detail endpoint: true when the campaign is stuck in sending because its send job failed or vanished (no worker is draining it), so it can be resumed via POST /:id/resume. Absent on list responses and for any non-sending campaign.

scheduledImmediatelyboolean

Computed flag, set only on the POST /:id/schedule response: true when the requested sendAt was already in the past, so the campaign fires immediately instead of waiting. Absent (never false) in the nominal case where sendAt is in the future and the campaign is scheduled for later.

scheduleJobLostboolean

Computed flag, set only on the campaign detail endpoint: true when the campaign is stuck in scheduled past its due date because its delayed trigger vanished (no job will fire it). An hourly safety-net sweep re-arms it automatically, so this is informational and self-heals. Absent on list responses and for any non-scheduled or not-yet-due campaign.

Example response

{
  "application": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Summer menu launch",
  "description": "Promote the new summer menu to recent visitors.",
  "channels": [
    "google",
    "apple"
  ],
  "targeting": {
    "minPoints": 100,
    "maxPoints": 500,
    "minVisits": 3,
    "rewardTierIds": [
      "550e8400-e29b-41d4-a716-446655440000"
    ]
  },
  "content": {
    "header": "New summer menu",
    "body": "Come and taste our new summer menu this week."
  },
  "sendAt": "2026-06-23T10:00:00Z",
  "status": "draft",
  "audienceSnapshotCount": 1234,
  "conversionWindowDays": 7,
  "sentAt": "2026-06-15T14:30:00Z",
  "scheduledImmediately": true
}

Changes

No recorded changes to this operation across all 1 revision of this API.