Skip to main content

Create Campaign

Create a push campaign as a draft. Creating never sends — use Send Campaign when you are ready.

Most teams build campaigns in the Arsel Dashboard. Use the API when campaigns are generated programmatically.

Endpoint

POST /push/campaigns

Returns: 201 Created

Headers

HeaderValueRequired
AuthorizationBearer <your-api-key>Yes
Content-Typeapplication/jsonYes

Body Parameters

Required

ParameterTypeDescription
namestringInternal campaign name. Max 100 characters. Not shown to recipients.
titlestringNotification title. 1–200 characters.
bodystringNotification body. 1–1000 characters.

Content

ParameterTypeDescription
descriptionstringInternal note.
image_urlstringLarge image. HTTPS only.
icon_urlstringSmall icon. HTTPS only.
deep_linkstringOpened on a body tap. Max 2048 characters.
android_channel_idstringAndroid notification channel id. Max 128 characters.
action_buttonsobject[]Up to 3 tappable buttons.
data_payloadobjectFlat string→string map. Keys starting arsel_, google, or gcm are rejected.

Audience

ParameterTypeDescription
list_idsstring[]List IDs to target.
tag_idsstring[]Tag IDs to target.
segment_idsstring[]Segment IDs to target.
target_platformsstring[]Restrict to android, ios, and/or web. Omit for all.
smart_sending_enabledbooleanSkip contacts who recently received a push, respecting your frequency cap.

Delivery

ParameterTypeDescription
ttl_secondsintegerHow long delivery may be retried, 602419200 (28 days).
prioritystringhigh or normal.
throttle_minutesintegerSpread the send over N minutes.
What throttle_minutes is for

Throttling does not protect Arsel — per-organization fair scheduling already does that. It protects your backend from your entire audience opening the app at once and hitting your API simultaneously. Set it based on your own capacity.

No merge tags in push

Push content is static. {{firstName}} and other merge variables are not interpolated — they would render literally on the device. Personalize by segmenting the audience instead.

{
"name": "Flash sale — 6h only",
"title": "Doors close at midnight",
"body": "Everything 40% off for the next six hours.",
"image_url": "https://cdn.example.com/sale.png",
"deep_link": "myapp://sale",
"list_ids": ["0192a1b2-c3d4-7e5f-9000-abcdef123456"],
"target_platforms": ["android", "ios"],
"ttl_seconds": 21600,
"throttle_minutes": 15,
"smart_sending_enabled": true
}

Response

Returns the full campaign, with status: "Draft".

{
"id": "0192a1b2-c3d4-7e5f-9000-abcdef123456",
"name": "Flash sale — 6h only",
"description": null,
"title": "Doors close at midnight",
"body": "Everything 40% off for the next six hours.",
"image_url": "https://cdn.example.com/sale.png",
"icon_url": null,
"deep_link": "myapp://sale",
"android_channel_id": null,
"ttl_seconds": 21600,
"priority": "high",
"action_buttons": null,
"data_payload": null,
"target_platforms": ["android", "ios"],
"throttle_minutes": 15,
"status": "Draft",
"smart_sending_enabled": true,
"scheduled_at": null,
"sent_at": null,
"created_at": "2026-08-10T12:00:00.000Z",
"updated_at": "2026-08-10T12:00:00.000Z"
}

Campaign status

StatusMeaning
DraftCreated, not yet sent
ScheduledQueued for a future time
QueuedAccepted for immediate fan-out
SendingFan-out in progress
PausedTemporarily halted
SentFan-out complete
FailedFan-out failed
CancelledCancelled before completion
ArchivedArchived

Examples

curl -X POST "https://api.arsel.sa/v1/push/campaigns" \
-H "Authorization: Bearer be_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Flash sale — 6h only",
"title": "Doors close at midnight",
"body": "Everything 40% off for the next six hours.",
"list_ids": ["0192a1b2-c3d4-7e5f-9000-abcdef123456"]
}'

Error Responses

Returned for a title over 200 characters, a non-HTTPS image_url, more than 3 action_buttons, a reserved data_payload key, or a ttl_seconds outside 60–2419200.

{
"status_code": 422,
"name": "validation_error",
"message": "Validation failed"
}