API

SharePush REST API — Reference

Create, schedule, update and track push campaigns from your own backend: authentication, endpoints, request fields, responses, errors and rate limits.

REST API Reference

The SharePush REST API lets your backend do what the dashboard does: create a campaign, schedule it, send live updates and read its results. Every example below uses placeholders. Replace them with your own values.

Placeholder What it is Where to find it
<YOUR_API_TOKEN> Your secret API token Profile menu → API Tokens → Create New Token. It is shown once, copy it right away. See API Tokens & Permissions.
<SITE_UUID> The site's UUID, used to create campaigns Sites → open the site. The UUID is under the domain name.
<SITE_TOKEN> The site's public token, used to read stats The apiKey value in your SDK snippet (Settings → Installation).
<CAMPAIGN_ULID> The ID of one campaign Returned as campaign_ulid when you create the campaign.

#Basics

  • Base URL: https://api.sharepush.io/api/v1
  • Format: send and receive JSON. Always set Accept: application/json, so errors come back as JSON too.
  • Authentication: send your token in every request as a bearer token.
 1Authorization: Bearer <YOUR_API_TOKEN>

Keep the token server-side. It can create and send notifications to your audience. Never put it in browser JavaScript, a mobile app or a public repository.

#Endpoints

Method Path What it does Token permission
GET /ping Checks that your token works read
POST /create/campaign Creates a campaign (or updates one when you pass ulid) create (update when passing ulid)
POST /campaigns/<CAMPAIGN_ULID>/dispatch Sends a new update for a live campaign update
POST /campaigns/<CAMPAIGN_ULID>/complete Closes a live campaign update
GET /campaigns/stats Reads delivery and click counts for a campaign read

#Token permissions

A token has one or more permissions: read, create, update, delete. New tokens get read only, so add create and update if you want to send campaigns. A token can also be limited to some of your sites. In that case, calls about any other site return 403. Full details in API Tokens & Permissions.


#1. Check your token

GET /ping

Run this first. It changes nothing and is safe to call anytime.

 1curl -X GET "https://api.sharepush.io/api/v1/ping" \
 2  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
 3  -H "Accept: application/json"

Response 200

 1{
 2  "status": "success",
 3  "message": "Your API Token is valid!",
 4  "timestamp": "2026-10-09T10:15:00+00:00"
 5}

#2. Create a campaign

POST /create/campaign

Creates a campaign on one of your sites, then sends it now, schedules it, or saves it as a draft.

#Request fields

Field Type Required Notes
uuid string yes The site's UUID (<SITE_UUID>).
name string yes Internal name, shown only in your dashboard. Max 255 characters.
title string yes Notification title. Max 65 characters.
body string yes Notification text. Max 160 characters.
action_url URL yes Where a click takes the subscriber.
send_type string yes immediate (send now), schedule (send at scheduled_at) or draft (save only).
scheduled_at date when send_type is schedule Must be in the future. Use ISO 8601 with a timezone offset, e.g. 2026-10-10T09:00:00+02:00.
type string no standard (default) or live. A live campaign can receive later updates via dispatch.
image_url URL no Large image shown in the notification, where the browser supports it.
icon_url URL no Small icon next to the notification.
bounce_url string no A page on your site, running the SharePush SDK, that every click passes through before reaching action_url. A path (/go) or a full URL. See Bounce URL.
prefill boolean no When true, adds utm_source=sharepush&utm_medium=push&utm_campaign=<title-slug> to action_url.
renotify boolean no Live campaigns only: alert the subscriber again when a newer update replaces the previous one.
filters object no Sends only to matching subscribers. See Targeting filters.
ulid string no Pass a campaign's ULID to update it instead of creating a new one. See Update a campaign.

#Example

 1curl -X POST "https://api.sharepush.io/api/v1/create/campaign" \
 2  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
 3  -H "Accept: application/json" \
 4  -H "Content-Type: application/json" \
 5  -d '{
 6    "uuid": "<SITE_UUID>",
 7    "type": "standard",
 8    "name": "Promo Friday",
 9    "title": "New Drop Is Live",
10    "body": "Tap to discover today'\''s best offer.",
11    "action_url": "https://example.com/offers",
12    "send_type": "immediate",
13    "prefill": true,
14    "filters": {
15      "browsers": ["Chrome", "Safari"],
16      "os": ["iOS", "Android"],
17      "countries": ["US", "IT"]
18    }
19  }'

The same request in JavaScript (Node 18+) and PHP:

 1const response = await fetch("https://api.sharepush.io/api/v1/create/campaign", {
 2  method: "POST",
 3  headers: {
 4    Authorization: "Bearer <YOUR_API_TOKEN>",
 5    Accept: "application/json",
 6    "Content-Type": "application/json",
 7  },
 8  body: JSON.stringify({
 9    uuid: "<SITE_UUID>",
10    name: "Promo Friday",
11    title: "New Drop Is Live",
12    body: "Tap to discover today's best offer.",
13    action_url: "https://example.com/offers",
14    send_type: "immediate",
15  }),
16});
17
18const result = await response.json();
19console.log(result.campaign_ulid); // keep it for updates, live dispatches and stats
 1<?php
 2
 3$ch = curl_init("https://api.sharepush.io/api/v1/create/campaign");
 4curl_setopt_array($ch, [
 5    CURLOPT_POST => true,
 6    CURLOPT_RETURNTRANSFER => true,
 7    CURLOPT_HTTPHEADER => [
 8        "Authorization: Bearer <YOUR_API_TOKEN>",
 9        "Accept: application/json",
10        "Content-Type: application/json",
11    ],
12    CURLOPT_POSTFIELDS => json_encode([
13        "uuid" => "<SITE_UUID>",
14        "name" => "Promo Friday",
15        "title" => "New Drop Is Live",
16        "body" => "Tap to discover today's best offer.",
17        "action_url" => "https://example.com/offers",
18        "send_type" => "immediate",
19    ]),
20]);
21
22$result = json_decode(curl_exec($ch), true);
23curl_close($ch);
24
25echo $result["campaign_ulid"];

Response 201 (200 when updating)

 1{
 2  "success": true,
 3  "message": "Campaign created and broadcast started.",
 4  "campaign_id": 1234,
 5  "campaign_ulid": "01JABCDEF0123456789XYZABCD",
 6  "final_url": "https://example.com/offers?utm_source=sharepush&utm_medium=push&utm_campaign=new-drop-is-live"
 7}

Save campaign_ulid: you need it to update the campaign, send live updates and complete it. final_url is the click URL after prefill was applied.

#Schedule for later

Set send_type to schedule and add scheduled_at:

 1{
 2  "uuid": "<SITE_UUID>",
 3  "name": "Weekend Sale",
 4  "title": "Weekend Sale Starts Now",
 5  "body": "Up to 40% off until Sunday night.",
 6  "action_url": "https://example.com/sale",
 7  "send_type": "schedule",
 8  "scheduled_at": "2026-10-10T09:00:00+02:00"
 9}

#Update a campaign

Send the same request with the campaign's ulid added. The token needs the update permission, and uuid must be the site the campaign belongs to.

 1{
 2  "ulid": "<CAMPAIGN_ULID>",
 3  "uuid": "<SITE_UUID>",
 4  "name": "Promo Friday Updated",
 5  "title": "Offer Extended",
 6  "body": "Final hours: claim your discount now.",
 7  "action_url": "https://example.com/offers/final-hours",
 8  "send_type": "draft"
 9}

Every update follows its send_type. With immediate the notification is sent again to your audience. Use draft to change a campaign without sending it, and schedule to move it to a new time.

#Targeting filters

filters limits who receives the notification. Every key is optional. An empty or missing list means "everyone".

Key Example values
browsers ["Chrome", "Safari", "Firefox", "Edge"]
os ["Android", "iOS", "Windows", "macOS"]
countries Two-letter country codes: ["US", "IT", "DE"]

Use the same names that appear in your dashboard reports. Filters apply to every send type and to live dispatches.


#3. Send a live update

POST /campaigns/<CAMPAIGN_ULID>/dispatch

Live campaigns ("type": "live") are made for news that keeps developing, such as a match, an election or a breaking story. Each dispatch sends a new notification that replaces the previous one on the subscriber's device instead of stacking up.

Field Type Required Notes
title string yes Max 65 characters.
body string yes Max 160 characters.
image_url URL no
renotify boolean no true makes the device alert again (sound or vibration) for this update.
filters object no Same as Targeting filters.
 1curl -X POST "https://api.sharepush.io/api/v1/campaigns/<CAMPAIGN_ULID>/dispatch" \
 2  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
 3  -H "Accept: application/json" \
 4  -H "Content-Type: application/json" \
 5  -d '{
 6    "title": "Live Update",
 7    "body": "Second half underway: 1-0.",
 8    "renotify": true
 9  }'

Response 200

 1{
 2  "success": true,
 3  "message": "Live update for the campaign dispatched successfully.",
 4  "campaign": "<CAMPAIGN_ULID>"
 5}

#Limit: 5 sends per live campaign

A live campaign can send 5 notifications in total, counting the first one sent when it was created. Once all 5 have been sent, the next dispatch call closes the campaign instead of sending, and still returns 200:

 1{
 2  "success": false,
 3  "cap_reached": true,
 4  "message": "Max Live Dispatches Reached, Campaign Completed. Max live updates: 5.",
 5  "campaign": "<CAMPAIGN_ULID>",
 6  "campaign_status": "completed"
 7}

Check the success field, not only the HTTP status. To keep going, create a new live campaign.

Calling dispatch on a standard campaign returns 400.


#4. Complete a live campaign

POST /campaigns/<CAMPAIGN_ULID>/complete

Closes a live campaign when the story is over. No body needed.

 1curl -X POST "https://api.sharepush.io/api/v1/campaigns/<CAMPAIGN_ULID>/complete" \
 2  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
 3  -H "Accept: application/json"

Response 200

 1{
 2  "success": true,
 3  "message": "Campaign marked as completed successfully.",
 4  "campaign": "<CAMPAIGN_ULID>"
 5}

#5. Read campaign stats

GET /campaigns/stats?site_token=<SITE_TOKEN>&title=<TITLE>

Finds a campaign by its title on a site and returns its counters. It's built for CMS integrations that know an article's title but not the campaign's ID.

Query parameter Required Notes
site_token yes The site's public token (<SITE_TOKEN>), not the UUID.
title yes The campaign title, matched exactly.
 1curl -G "https://api.sharepush.io/api/v1/campaigns/stats" \
 2  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
 3  -H "Accept: application/json" \
 4  --data-urlencode "site_token=<SITE_TOKEN>" \
 5  --data-urlencode "title=New Drop Is Live"

Response 200

 1{
 2  "data": {
 3    "img": "https://example.com/images/drop.jpg",
 4    "title": "New Drop Is Live",
 5    "description": "Tap to discover today's best offer.",
 6    "send_time": "2026-10-09 10:15:00",
 7    "status": "sent",
 8    "sent": true,
 9    "impression": 15230,
10    "success": 15230,
11    "failure": 112,
12    "delivered": 13980,
13    "click": 642,
14    "ctr": "4,22"
15  },
16  "generated_at": "2026-10-09T10:30:00+00:00"
17}
Field Meaning
status draft, scheduled, sending, sent or failed.
sent true once the campaign has started sending.
impression / success Notifications accepted by the push services.
failure Notifications the push services rejected.
delivered Notifications that reached the device.
click Clicks on the notification.
ctr click / impression as a percentage, with a comma as the decimal separator ("4,22" = 4.22%).

Good to know:

  • If several campaigns share the title, the most recent one is returned. Only the first 65 characters of the title are compared.
  • No match returns "data": null with status 200, not an error.
  • Results are cached for about 25 minutes, so polling every 15 minutes is fine. Polling faster won't give fresher numbers.

#Errors

Errors come back as JSON with an error or message field explaining what went wrong.

Status When
400 Dispatch or complete called on a campaign that isn't live.
401 Token missing, invalid or expired, or its owner is no longer a member of your team.
403 The token lacks the needed permission or access to that site, the site isn't yours, or your plan doesn't include API access.
404 Campaign or site not found for your team.
422 A field failed validation. The response lists each field with its error (see below). Also returned when uuid doesn't match the campaign's site on an update.
429 Rate limit reached. The message says how many seconds to wait.
500 Server error. See Retrying safely.

A validation error looks like this:

 1{
 2  "message": "The title field must not be greater than 65 characters.",
 3  "errors": {
 4    "title": ["The title field must not be greater than 65 characters."]
 5  }
 6}

#Retrying safely

A 500 from create includes a retryable flag:

  • "error": "Unable to save the campaign, please retry": nothing was saved, so you can safely send the same request again.
  • "error": "Campaign saved but delivery could not be started": the campaign exists, and its campaign_ulid is in the response. Don't create it again, or subscribers may get it twice. If retryable is true, retry as an update with that ulid. If it's false (an immediate send that may have partly gone out), check the campaign in your dashboard first.

#Rate limits

  • Per hour: each team, and each IP address, gets a request allowance set by your plan. Over the limit you get 429 with the number of seconds to wait.
  • Stats: /campaigns/stats also allows at most 120 requests per minute.
  • No API access: if your plan doesn't include the API, every call returns 403. Upgrade from the pricing page to enable it.