A campaign sends one approved WhatsApp template to an audience of contact lists, segments and individual contacts. You create it as a DRAFT, then either schedule it for later or run it now, and follow it through the delivery endpoints.
The lifecycle: DRAFT → SCHEDULED or IN_PROGRESS → FINISHED. A running or scheduled campaign can be cancelled. Only a draft can be edited or deleted — updating anything else answers 409. FAILED and STOPPED exist in the status list, but none of these endpoints sets them.
Endpoints
GET/campaignsList campaignsGET/campaigns/{campaignId}Retrieve a campaignPOST/campaignsCreate a campaignPUT/campaigns/{campaignId}Update a campaignPOST/campaigns/{campaignId}/scheduleSchedule a campaignPOST/campaigns/{campaignId}/runsSend a campaign nowPOST/campaigns/{campaignId}/cancelCancel a campaignGET/campaigns/{campaignId}/delivery/summaryRetrieve delivery countsGET/campaigns/{campaignId}/deliveryList deliveriesGET/campaigns/{campaignId}/delivery/{deliveryId}Retrieve a deliveryPOST/campaigns/{campaignId}/target-previewPreview the audienceDELETE/campaigns/{campaignId}Delete a campaignThe campaign object
The response carries a message summary (template name and language), not the full payloadJson: send that on create and update.
Attributes
idintegerUnique identifier of the campaign.orgIdintegerYour organisation.namestringCampaign name.campaignTypestringThe kind of campaign, a free string. Defaults toBROADCAST: one template message to an audience.channelConfigIdintegerThe WhatsApp channel line the campaign sends through.fallbackChannelConfigIdintegernullableThe channel line used for the fallback message, if one is set.statusstringWhere the campaign is in its life. Only aDRAFTcan be edited.One of:DRAFTSCHEDULEDIN_PROGRESSFINISHEDSTOPPEDCANCELLEDFAILEDtargetingobjectWho receives it. You can combine lists, segments and individual contacts.messageobjectnullableA summary of the message, not the fullpayloadJson.nulluntil a message is saved.createdByobjectnullableWho created the campaign.wizardStatejsonnullableWhatever the dashboard’s campaign wizard saved so it can resume a draft. Natiq stores it as given.scheduledAtstringnullableWhen a scheduled campaign sends (ISO 8601).startedAtstringnullableWhen sending began.finishedAtstringnullableWhen sending ended.createdAtstringWhen the campaign was created.updatedAtstringWhen it was last changed.
{
"id": 301,
"orgId": 12,
"name": "Order shipped — November",
"campaignType": "BROADCAST",
"channelConfigId": 22,
"status": "DRAFT",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"fallbackChannelConfigId": null,
"message": {
"channelType": "WHATSAPP",
"templateName": "order_shipped",
"language": "ar",
"headerMediaUrl": null
},
"createdBy": {
"userId": 41,
"username": "layla",
"email": "layla@example.com"
},
"wizardState": null,
"scheduledAt": null,
"startedAt": null,
"finishedAt": null,
"createdAt": "2026-11-06T12:00:00Z",
"updatedAt": "2026-11-06T12:00:00Z"
}
List campaigns
Returns a page of campaigns, newest first.
campaigns.campaign:read Offset paginatedQuery parameters
pageintegerZero-based page number. Default0.sizeintegerPage size. Default20; keep it at100or below.namestringOnly campaigns whose name contains this text, case-insensitive.statusstringOnly campaigns in this status.One of:DRAFTSCHEDULEDIN_PROGRESSFINISHEDSTOPPEDCANCELLEDFAILEDchannelConfigIdintegerOnly campaigns on this channel line.createdFromstringOnly campaigns created at or after this ISO 8601 instant.createdTostringOnly campaigns created at or before this ISO 8601 instant.
Returns
200A page of results.
Errors
- 400
INVALID_REQUESTThe `status` is not a known value, or `createdFrom` is after `createdTo`.
curl -X GET "https://api.cx.na6iq.com/api/v1/campaigns?page=0&size=25" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns?page=0&size=25', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.get(
"https://api.cx.na6iq.com/api/v1/campaigns?page=0&size=25",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"data": [
{
"id": 301,
"orgId": 12,
"name": "Order shipped — November",
"campaignType": "BROADCAST",
"channelConfigId": 22,
"status": "DRAFT",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"fallbackChannelConfigId": null,
"message": {
"channelType": "WHATSAPP",
"templateName": "order_shipped",
"language": "ar",
"headerMediaUrl": null
},
"createdBy": {
"userId": 41,
"username": "layla",
"email": "layla@example.com"
},
"wizardState": null,
"scheduledAt": null,
"startedAt": null,
"finishedAt": null,
"createdAt": "2026-11-06T12:00:00Z",
"updatedAt": "2026-11-06T12:00:00Z"
}
],
"page": 0,
"size": 20,
"totalElements": 1,
"totalPages": 1
}
Retrieve a campaign
Returns one campaign.
campaigns.campaign:readPath parameters
campaignIdintegerrequiredThe campaign’sid.
Returns
200The campaign object.
Errors
- 404
CAMPAIGN_NOT_FOUNDNo campaign with this ID in your organisation.
curl -X GET "https://api.cx.na6iq.com/api/v1/campaigns/42" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns/42', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.get(
"https://api.cx.na6iq.com/api/v1/campaigns/42",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"id": 301,
"orgId": 12,
"name": "Order shipped — November",
"campaignType": "BROADCAST",
"channelConfigId": 22,
"status": "DRAFT",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"fallbackChannelConfigId": null,
"message": {
"channelType": "WHATSAPP",
"templateName": "order_shipped",
"language": "ar",
"headerMediaUrl": null
},
"createdBy": {
"userId": 41,
"username": "layla",
"email": "layla@example.com"
},
"wizardState": null,
"scheduledAt": null,
"startedAt": null,
"finishedAt": null,
"createdAt": "2026-11-06T12:00:00Z",
"updatedAt": "2026-11-06T12:00:00Z"
}
Create a campaign
Creates a campaign in DRAFT. Nothing is sent until you schedule it or run it. No field is required on save: a draft saves incomplete, and scheduling checks it.
campaigns.campaign:writeRequest body
namestringCampaign name.channelConfigIdintegerThe WhatsApp channel line to send through.campaignTypestringDefaults toBROADCAST.targetingobjectThe audience. Every array is optional.messageobjectWhat to send.fallbackChannelConfigIdintegerA second channel line to use for the fallback message.fallbackMessageobjectThe fallback message to send on that line.wizardStatejsonFree-form state for the dashboard’s campaign wizard. Natiq stores it as given.
Returns
201The campaign object.
Errors
- 404
CHANNEL_CONFIG_NOT_FOUNDThe `channelConfigId` (or fallback line) is not a channel in your organisation. - 404
CONTACT_LIST_NOT_FOUNDA targeting list, segment or contact does not exist. The code is `CONTACT_LIST_NOT_FOUND`, `SEGMENT_NOT_FOUND` or `CONTACT_NOT_FOUND`, depending on which one is missing. - 409
CAMPAIGN_CHANNEL_MISMATCHThe message’s channel type does not match the channel line. - 400
INVALID_REQUESTThe body is not valid JSON.
curl -X POST "https://api.cx.na6iq.com/api/v1/campaigns" \
-H "Authorization: Bearer $NATIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Order shipped — November",
"channelConfigId": 22,
"campaignType": "BROADCAST",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"message": {
"channelType": "WHATSAPP",
"payloadJson": "{\"templateName\":\"order_shipped\",\"language\":\"ar\",\"components\":[{\"type\":\"body\",\"parameters\":[{\"type\":\"text\",\"text\":\"ليلى\"},{\"type\":\"text\",\"text\":\"A-1001\"}]}]}"
}
}'
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Order shipped — November",
"channelConfigId": 22,
"campaignType": "BROADCAST",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"message": {
"channelType": "WHATSAPP",
"payloadJson": "{\"templateName\":\"order_shipped\",\"language\":\"ar\",\"components\":[{\"type\":\"body\",\"parameters\":[{\"type\":\"text\",\"text\":\"ليلى\"},{\"type\":\"text\",\"text\":\"A-1001\"}]}]}"
}
}),
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.post(
"https://api.cx.na6iq.com/api/v1/campaigns",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
json={
"name": "Order shipped — November",
"channelConfigId": 22,
"campaignType": "BROADCAST",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"message": {
"channelType": "WHATSAPP",
"payloadJson": "{\"templateName\":\"order_shipped\",\"language\":\"ar\",\"components\":[{\"type\":\"body\",\"parameters\":[{\"type\":\"text\",\"text\":\"ليلى\"},{\"type\":\"text\",\"text\":\"A-1001\"}]}]}"
}
},
)
res.raise_for_status()
data = res.json()
{
"id": 301,
"orgId": 12,
"name": "Order shipped — November",
"campaignType": "BROADCAST",
"channelConfigId": 22,
"status": "DRAFT",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"fallbackChannelConfigId": null,
"message": {
"channelType": "WHATSAPP",
"templateName": "order_shipped",
"language": "ar",
"headerMediaUrl": null
},
"createdBy": {
"userId": 41,
"username": "layla",
"email": "layla@example.com"
},
"wizardState": null,
"scheduledAt": null,
"startedAt": null,
"finishedAt": null,
"createdAt": "2026-11-06T12:00:00Z",
"updatedAt": "2026-11-06T12:00:00Z"
}
Update a campaign
Updates a draft. name and targeting are replaced, so send them every time; if message is omitted the stored message is kept. Allowed only while the status is DRAFT. No field is required: a draft saves incomplete, and scheduling checks it.
campaigns.campaign:writePath parameters
campaignIdintegerrequiredThe campaign’sid.
Request body
namestringCampaign name.channelConfigIdintegerThe WhatsApp channel line to send through.campaignTypestringDefaults toBROADCAST.targetingobjectThe audience. Every array is optional.messageobjectWhat to send.fallbackChannelConfigIdintegerA second channel line to use for the fallback message.fallbackMessageobjectThe fallback message to send on that line.wizardStatejsonFree-form state for the dashboard’s campaign wizard. Natiq stores it as given.
Returns
200The campaign object.
Errors
- 409
CAMPAIGN_NOT_EDITABLEOnly drafts can be updated, and this campaign has left `DRAFT`. - 404
CAMPAIGN_NOT_FOUNDNo campaign with this ID in your organisation. - 404
CHANNEL_CONFIG_NOT_FOUNDThe `channelConfigId` (or fallback line) is not a channel in your organisation. - 404
CONTACT_LIST_NOT_FOUNDA targeting list, segment or contact does not exist. The code is `CONTACT_LIST_NOT_FOUND`, `SEGMENT_NOT_FOUND` or `CONTACT_NOT_FOUND`, depending on which one is missing. - 409
CAMPAIGN_CHANNEL_MISMATCHThe message’s channel type does not match the channel line. - 400
INVALID_REQUESTThe body is not valid JSON.
curl -X PUT "https://api.cx.na6iq.com/api/v1/campaigns/42" \
-H "Authorization: Bearer $NATIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Order shipped — November (final)",
"channelConfigId": 22,
"campaignType": "BROADCAST",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"message": {
"channelType": "WHATSAPP",
"payloadJson": "{\"templateName\":\"order_shipped\",\"language\":\"ar\",\"components\":[{\"type\":\"body\",\"parameters\":[{\"type\":\"text\",\"text\":\"ليلى\"},{\"type\":\"text\",\"text\":\"A-1001\"}]}]}"
}
}'
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns/42', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Order shipped — November (final)",
"channelConfigId": 22,
"campaignType": "BROADCAST",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"message": {
"channelType": "WHATSAPP",
"payloadJson": "{\"templateName\":\"order_shipped\",\"language\":\"ar\",\"components\":[{\"type\":\"body\",\"parameters\":[{\"type\":\"text\",\"text\":\"ليلى\"},{\"type\":\"text\",\"text\":\"A-1001\"}]}]}"
}
}),
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.put(
"https://api.cx.na6iq.com/api/v1/campaigns/42",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
json={
"name": "Order shipped — November (final)",
"channelConfigId": 22,
"campaignType": "BROADCAST",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"message": {
"channelType": "WHATSAPP",
"payloadJson": "{\"templateName\":\"order_shipped\",\"language\":\"ar\",\"components\":[{\"type\":\"body\",\"parameters\":[{\"type\":\"text\",\"text\":\"ليلى\"},{\"type\":\"text\",\"text\":\"A-1001\"}]}]}"
}
},
)
res.raise_for_status()
data = res.json()
{
"id": 301,
"orgId": 12,
"name": "Order shipped — November (final)",
"campaignType": "BROADCAST",
"channelConfigId": 22,
"status": "DRAFT",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"fallbackChannelConfigId": null,
"message": {
"channelType": "WHATSAPP",
"templateName": "order_shipped",
"language": "ar",
"headerMediaUrl": null
},
"createdBy": {
"userId": 41,
"username": "layla",
"email": "layla@example.com"
},
"wizardState": null,
"scheduledAt": null,
"startedAt": null,
"finishedAt": null,
"createdAt": "2026-11-06T12:00:00Z",
"updatedAt": "2026-11-06T12:00:00Z"
}
Schedule a campaign
Sets the time the campaign sends and moves it to SCHEDULED. Scheduling is its own permission, separate from editing.
campaigns.campaign:schedulePath parameters
campaignIdintegerrequiredThe campaign’sid.
Request body
scheduledAtstringrequiredWhen to send, as an ISO 8601 instant.
Returns
200The campaign object.
Errors
- 409
CAMPAIGN_INVALID_STATUSOnly a `DRAFT` can be scheduled. - 400
CAMPAIGN_INCOMPLETEThe draft is missing something it needs. `error.details` lists what: the name, channel, audience or message. - 400
VALIDATION_FAILED`scheduledAt` is missing. - 404
CAMPAIGN_NOT_FOUNDNo campaign with this ID in your organisation.
curl -X POST "https://api.cx.na6iq.com/api/v1/campaigns/42/schedule" \
-H "Authorization: Bearer $NATIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scheduledAt": "2026-11-10T07:00:00Z"
}'
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns/42/schedule', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"scheduledAt": "2026-11-10T07:00:00Z"
}),
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.post(
"https://api.cx.na6iq.com/api/v1/campaigns/42/schedule",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
json={
"scheduledAt": "2026-11-10T07:00:00Z"
},
)
res.raise_for_status()
data = res.json()
{
"id": 301,
"orgId": 12,
"name": "Order shipped — November",
"campaignType": "BROADCAST",
"channelConfigId": 22,
"status": "SCHEDULED",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"fallbackChannelConfigId": null,
"message": {
"channelType": "WHATSAPP",
"templateName": "order_shipped",
"language": "ar",
"headerMediaUrl": null
},
"createdBy": {
"userId": 41,
"username": "layla",
"email": "layla@example.com"
},
"wizardState": null,
"scheduledAt": "2026-11-10T07:00:00Z",
"startedAt": null,
"finishedAt": null,
"createdAt": "2026-11-06T12:00:00Z",
"updatedAt": "2026-11-06T12:00:00Z"
}
Send a campaign now
Dispatches a run immediately. Allowed from DRAFT, SCHEDULED or IN_PROGRESS. It answers 202 Accepted: the run is prepared before the response returns (READY), materializedCount reports how many deliveries were created, and sending continues in the background. Follow progress with Retrieve delivery counts.
campaigns.campaign:schedulePath parameters
campaignIdintegerrequiredThe campaign’sid.
Returns
202The campaign object.
Errors
- 409
CAMPAIGN_INVALID_STATUSThe campaign is not in `DRAFT`, `SCHEDULED` or `IN_PROGRESS`. - 409
CAMPAIGN_MESSAGE_REQUIREDThe campaign has no message yet. - 409
CAMPAIGN_CHANNEL_REQUIREDThe campaign has no channel line yet. - 409
CAMPAIGN_CHANNEL_MISMATCHThe message’s channel type does not match the channel line. - 409
CAMPAIGN_TARGET_REQUIREDThe campaign has no audience yet. - 404
CHANNEL_CONFIG_NOT_FOUNDThe campaign’s channel line no longer exists in your organisation. - 404
CAMPAIGN_NOT_FOUNDNo campaign with this ID in your organisation.
curl -X POST "https://api.cx.na6iq.com/api/v1/campaigns/42/runs" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns/42/runs', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.post(
"https://api.cx.na6iq.com/api/v1/campaigns/42/runs",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"id": 884,
"campaignId": 301,
"status": "READY",
"materializedCount": 470
}
Cancel a campaign
Stops a live campaign — one that is scheduled or sending — and returns it. Messages already sent are not recalled.
campaigns.campaign:writePath parameters
campaignIdintegerrequiredThe campaign’sid.
Returns
200The campaign object.
Errors
- 409
CAMPAIGN_INVALID_STATUSOnly a `SCHEDULED` or `IN_PROGRESS` campaign can be cancelled. - 404
CAMPAIGN_NOT_FOUNDNo campaign with this ID in your organisation.
curl -X POST "https://api.cx.na6iq.com/api/v1/campaigns/42/cancel" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns/42/cancel', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.post(
"https://api.cx.na6iq.com/api/v1/campaigns/42/cancel",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"id": 301,
"orgId": 12,
"name": "Order shipped — November",
"campaignType": "BROADCAST",
"channelConfigId": 22,
"status": "CANCELLED",
"targeting": {
"listIds": [
7
],
"segmentIds": [
12
],
"contactIds": []
},
"fallbackChannelConfigId": null,
"message": {
"channelType": "WHATSAPP",
"templateName": "order_shipped",
"language": "ar",
"headerMediaUrl": null
},
"createdBy": {
"userId": 41,
"username": "layla",
"email": "layla@example.com"
},
"wizardState": null,
"scheduledAt": null,
"startedAt": null,
"finishedAt": null,
"createdAt": "2026-11-06T12:00:00Z",
"updatedAt": "2026-11-06T12:00:00Z"
}
Retrieve delivery counts
Returns how many messages are in each delivery state.
campaigns.reports:readPath parameters
campaignIdintegerrequiredThe campaign’sid.
Returns
200The campaign object.
Errors
- 404
CAMPAIGN_NOT_FOUNDNo campaign with this ID in your organisation.
curl -X GET "https://api.cx.na6iq.com/api/v1/campaigns/42/delivery/summary" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns/42/delivery/summary', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.get(
"https://api.cx.na6iq.com/api/v1/campaigns/42/delivery/summary",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"total": 470,
"pending": 0,
"sent": 12,
"delivered": 301,
"read": 142,
"failed": 15,
"stopped": 0,
"cancelled": 0,
"updatedAt": "2026-11-10T07:12:30Z"
}
List deliveries
Returns one row per contact the campaign messaged, oldest first, as a plain array. Keyset paginated: pass the largest id on the page as afterId to get the next rows. Filter with status to find the failures. contactDisplayName and contactPhone can be null.
campaigns.reports:read Keyset paginatedPath parameters
campaignIdintegerrequiredThe campaign’sid.
Query parameters
afterIdintegerReturn rows after this ID.0or omitted starts from the oldest.sizeintegerRows per page, clamped to1–100. Default50.statusstringOnly rows in this state. An exact match, so use uppercase.One of:PENDINGSENTDELIVEREDREADFAILEDSTOPPEDCANCELLED
Returns
200The campaign object.
Errors
- 404
CAMPAIGN_NOT_FOUNDNo campaign with this ID in your organisation.
curl -X GET "https://api.cx.na6iq.com/api/v1/campaigns/42/delivery?size=25" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns/42/delivery?size=25', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.get(
"https://api.cx.na6iq.com/api/v1/campaigns/42/delivery?size=25",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
[
{
"id": 9120,
"campaignId": 301,
"dispatchRunId": 884,
"contactId": 1842,
"contactDisplayName": "Layla Haddad",
"contactPhone": "+966500000001",
"status": "DELIVERED",
"sentAt": "2026-11-10T07:00:04Z",
"deliveredAt": "2026-11-10T07:00:06Z",
"readAt": null,
"failedAt": null,
"errorMessage": null,
"createdAt": "2026-11-10T07:00:01Z"
}
]
Retrieve a delivery
Returns one delivery row.
campaigns.reports:readPath parameters
campaignIdintegerrequiredThe campaign’sid.deliveryIdintegerrequiredThe delivery row’sid.
Returns
200The campaign object.
Errors
- 404
DELIVERY_NOT_FOUNDNo delivery with this ID on the campaign. - 404
CAMPAIGN_NOT_FOUNDNo campaign with this ID in your organisation.
curl -X GET "https://api.cx.na6iq.com/api/v1/campaigns/42/delivery/42" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns/42/delivery/42', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.get(
"https://api.cx.na6iq.com/api/v1/campaigns/42/delivery/42",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"id": 9120,
"campaignId": 301,
"dispatchRunId": 884,
"contactId": 1842,
"contactDisplayName": "Layla Haddad",
"contactPhone": "+966500000001",
"status": "DELIVERED",
"sentAt": "2026-11-10T07:00:04Z",
"deliveredAt": "2026-11-10T07:00:06Z",
"readAt": null,
"failedAt": null,
"errorMessage": null,
"createdAt": "2026-11-10T07:00:01Z"
}
Preview the audience
Returns a page of the contacts the campaign would reach with its current targeting. Nothing is sent.
campaigns.campaign:read Offset paginatedPath parameters
campaignIdintegerrequiredThe campaign’sid.
Query parameters
pageintegerZero-based page number. Default0.sizeintegerPage size.
Returns
200A page of results.
Errors
- 404
CAMPAIGN_NOT_FOUNDNo campaign with this ID in your organisation.
curl -X POST "https://api.cx.na6iq.com/api/v1/campaigns/42/target-preview?page=0&size=25" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns/42/target-preview?page=0&size=25', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.post(
"https://api.cx.na6iq.com/api/v1/campaigns/42/target-preview?page=0&size=25",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"data": [
{
"id": 1842,
"displayName": "Layla Haddad",
"email": "layla@example.com",
"phone": "+966500000001",
"status": "customer"
}
],
"page": 0,
"size": 20,
"totalElements": 470,
"totalPages": 24
}
Delete a campaign
Deletes a campaign. Only a DRAFT can be deleted.
campaigns.campaign:writePath parameters
campaignIdintegerrequiredThe campaign’sid.
Returns
204The campaign is deleted.
Errors
- 409
CAMPAIGN_NOT_DELETABLEThe campaign has left `DRAFT`. - 404
CAMPAIGN_NOT_FOUNDNo campaign with this ID in your organisation.
curl -X DELETE "https://api.cx.na6iq.com/api/v1/campaigns/42" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/campaigns/42', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
import os, requests
res = requests.delete(
"https://api.cx.na6iq.com/api/v1/campaigns/42",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()