Migrate from v5 to v2026-03-15

Migrate from v5 to v2026-03-15

This guide outlines the key changes when migrating your integration from the v5 API to the v2026-03-15 API.


Generic changes

Base URL

  • v5: https://api.omnisend.com/v5/
  • v2026-03-15: https://api.omnisend.com/api/

All endpoints, including products, categories, batches, and events, have moved to the /api/ base path.

Authentication

The API key header name has changed:

v5v2026-03-15
HeaderX-API-KEY: {key}Authorization: Omnisend-API-Key {key}
Version headerNot requiredOmnisend-Version: 2026-03-15 (required on every request)

v5 example:

curl --request GET \
  --url 'https://api.omnisend.com/v5/contacts' \
  --header 'X-API-KEY: YOUR-API-KEY'

v2026-03-15 example:

curl --request GET \
  --url 'https://api.omnisend.com/api/contacts' \
  --header 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
  --header 'Omnisend-Version: 2026-03-15'

Pagination

Pagination changed from URL-link-based to cursor-based:

v5v2026-03-15
Next pagepaging.next (full URL)paging.cursors.after (opaque token)
Previous pagepaging.previous (full URL)paging.cursors.before (opaque token)
More results indicatorValue in paging.nextpaging.hasMore: true

v5 response:

{
  "contacts": [...],
  "paging": {
    "next": "https://api.omnisend.com/v5/contacts?after=abc123",
    "previous": null,
    "limit": 100
  }
}

v2026-03-15 response:

{
  "contacts": [...],
  "paging": {
    "limit": 100,
    "hasMore": true,
    "cursors": {
      "after": "eyJpZCI6IjEyMyJ9",
      "before": "eyJpZCI6IjEifQ=="
    }
  }
}

Pass the cursor token as a query parameter: GET /api/contacts?after=eyJpZCI6IjEyMyJ9

Error responses

v5v2026-03-15
Format{error, fields}RFC 9457 {type, title, status, detail, errors[]}

Resource changes

Contacts

Base path: /v5/contacts/api/contacts

Endpoint changes

v5v2026-03-15Notes
GET /v5/contacts/{contactID}GET /api/contacts/{id}Path parameter renamed
PATCH /v5/contacts/{contactID}PATCH /api/contacts/{id}Path parameter renamed
POST /v5/contactsPOST /api/contactsNo longer upserts; always creates. Returns 201.
POST /api/contacts/tagsNew: batch add tags
DELETE /api/contacts/tagsNew: batch remove tags

POST upsert behavior removed

In v5, POST /contacts with a contactID body field performed an upsert (update if exists, create if not). This behavior is removed. POST /contacts no longer accepts contactID and always creates a new contact.

Use PATCH /api/contacts/{id} as a direct replacement for the v5 upsert behavior.

Legacy top-level request fields removed

The following top-level fields are no longer accepted on POST /contacts and PATCH /contacts:

email, phone, phoneNumber, status, statusDate, optInDate, optInIP, creationDate, source

Use the identifiers array with per-identifier channels and consent instead.

sendWelcomeEmail removed

The sendWelcomeEmail field is removed. Welcome messages are now sent automatically when an identifier's channel is set to subscribed. To suppress welcome messages (e.g. during imports), use the per-identifier sendWelcomeMessage field.

tags field now replaces instead of appends

Behaviorv5v2026-03-15
"tags": ["a"]Appends "a" to existing tagsReplaces the entire tags array with ["a"]
"tags": []No-opClears all tags
tags omittedTags unchangedTags unchanged

Response field renames

v5 fieldv2026-03-15 field
ContactStatus.dateContactStatus.statusChangedAt
OptIn.dateOptIn.optInAt
Channel.statusDateChannel.statusChangedAt

Other field changes

Fieldv5v2026-03-15Notes
contactIDResponse fieldRemovedUse id instead
stateFree-form stringISO 3166-2 subdivision code (e.g., "CA")Format is now validated

Campaigns

Base path: /v5/campaigns/api/campaigns

Endpoint changes

v5 exposed campaigns as read-only. v2026-03-15 introduces full CRUD and lifecycle management:

v5v2026-03-15Notes
GET /v5/campaignsGET /api/campaignsList campaigns
GET /v5/campaigns/{campaignID}GET /api/campaigns/{id}Path parameter renamed
POST /api/campaignsNew: create campaign
PATCH /api/campaigns/{id}New: update campaign
DELETE /api/campaigns/{id}New: delete campaign
POST /api/campaigns/{id}/sendNew: send campaign
POST /api/campaigns/{id}/cancelNew: cancel campaign
POST /api/campaigns/{id}/copyNew: copy campaign

Response structure changes

Fieldv5v2026-03-15Notes
subjectLineTop-level stringRemovedMoved to content.email.subjectLine
tzoEnabledTop-level booleanRemovedMoved to sendingSettings.isTZOptimizationEnabled
startDateTop-level timestampRemovedRenamed to startedAt
endDateTop-level timestampRemovedRenamed to endedAt
sendStartDateTop-level timestampRemovedMoved to sendingSettings.scheduledAt
sendEndDateTop-level timestampRemoved
startedAtTop-level timestampRenamed from startDate
endedAtTop-level timestampRenamed from endDate
audienceObjectNew: includedSegmentIDs, excludedSegmentIDs
contentObjectNew: email/sms/push content configuration
sendingSettingsObjectNew: strategy, isTZOptimizationEnabled, scheduledAt
languageString (locale xx_XX)New
brandIDStringNew

Status enum changes

v5v2026-03-15
draftdraft
pending— (removed)
startedstarted
canceledcanceled
pausedpaused
sentsent
errorerror
onHoldonHold
archived— (removed)
splitTestingStarted— (removed)
splitTestingStopped— (removed)
splitTestingExpired— (removed)
stopped (new)
expired (new)
scheduled (new)

Type enum changes

v5v2026-03-15
standartregular
abTestabTest
booster (new)

Product Categories

Base path: /v5/product-categories/api/product-categories

Fieldv5v2026-03-15Notes
titlemaxLength: 100maxLength: 255Extended limit