API Documentation

Everything you need to send notifications and handle responses.

Quick Start

Create a topic in your dashboard, then send your first notification:

# Send a plain-text push

curl -d "Hello from my Pi!" https://www.iotpush.com/api/push/my-topic

Always use the full URL: https://www.iotpush.com/...

Three URL forms will appear to "almost work" but silently fail with"Redirecting..." — see Troubleshooting below for details.

  • http://...  →  308 redirect to https; curl drops POST body by default
  • iotpush.com/... (apex, no www)  →  307 redirect to www; same problem
  • iotpush.com/your-topic (no /api/push/)  →  wrong path entirely

Troubleshooting — "Redirecting..."

If your curl command prints Redirecting... and no notification arrives, your URL is triggering an HTTP redirect that silently drops the POST body. This is the single most common integration issue. Here's how to diagnose and fix it.

Why it happens

By default, curl does not follow redirects, and even with -L it converts POST to GET on 301/302 unless you also pass --post301 --post302 --post307. The same gotcha exists in many Arduino / ESP32 HTTP libraries, older Python requests versions, and some webhook platforms. The cleanest fix is to never trigger a redirect in the first place.

Cause matrix

URL you usedWhat the server doesOutcome
http://www.iotpush.com/api/push/my-topic308 → https://www.iotpush.com/...curl prints "Redirecting..." and stops
http://iotpush.com/api/push/my-topic308 → https → 307 → www (two hops)Body dropped on hop 2, even with -L
https://iotpush.com/api/push/my-topic307 → https://www.iotpush.com/...Body dropped unless --post307 is set
iotpush.com/your-topic (no /api/push/)Path doesn't exist404 / wrong route
https://www.iotpush.com/api/push/my-topicDirect hit — no redirect✅ 200 OK, notification delivered

Diagnose your own request

Run with -v to see the redirect chain, or --fail-with-body to surface real error responses:

# See exactly what the server returned (headers + body)
curl -v -d "test" https://www.iotpush.com/api/push/my-topic

# Treat 4xx/5xx as errors but still print the response body
curl --fail-with-body -sS \
     -d "test" \
     https://www.iotpush.com/api/push/my-topic

If you cannot change the URL

(e.g. legacy device, hard-coded webhook). Tell curl to follow redirects andpreserve the POST body across all redirect codes:

curl -L --post301 --post302 --post307 --post308 \
     -d "Hello from my Pi!" \
     http://iotpush.com/api/push/my-topic

Other common errors

StatusBodyFix
404Topic "X" not foundCreate the topic in your dashboard first
401Invalid API keyCheck the Authorization: Bearer token for private topics
405Method Not AllowedUse POST, not GET — push endpoints only accept POST
429Rate limit exceededYou hit your monthly cap; upgrade or wait

Send Notification

POST /api/push/{topic}

Send a push notification to all subscribers of a topic. Accepts plain text or a JSON body. Private topics require an Authorization header with the topic API key.

Authentication (private topics)

# Bearer token = your topic API key

Authorization: Bearer YOUR_TOPIC_API_KEY

JSON Body Fields

FieldTypeRequiredDescription
messagestringYesThe notification body text
titlestringNoNotification title shown in bold
prioritystringNolow · normal (default) · high · urgent
tagsstringNoComma-separated tags, e.g. "sensor,alert"
click_urlstringNoURL to open when the notification is tapped
actionsarrayNoInteractive action buttons (see Action Buttons)
callback_urlstringNoWebhook URL called when an action is tapped

Header Shortcuts

When sending plain text you can pass fields as HTTP headers instead of JSON.

HeaderDescriptionExample
TitleNotification titleAlert!
Prioritylow, normal, high, urgenthigh
TagsComma-separated tagswarning,sensor
ClickURL to open on taphttps://...

Response

{
  "success": true,
  "id": "31d902cf-...",        // message ID
  "receipt_id": "b06e8c90-...", // use to poll delivery status
  "topic": "my-topic",
  "timestamp": "2026-04-10T00:06:01Z",
  "subscribers": 8
}

Examples

Simple:

curl -d "Sensor triggered!" https://www.iotpush.com/api/push/my-topic

With headers:

curl -H "Title: Alert" -H "Priority: high" \
     -d "Temperature exceeded 80°C" \
     https://www.iotpush.com/api/push/my-topic

JSON body:

curl -H "Content-Type: application/json" \
     -d '{"title":"Alert","message":"Temp high!","priority":"high"}' \
     https://www.iotpush.com/api/push/my-topic

Private topic (with API key):

curl -H "Authorization: Bearer YOUR_TOPIC_API_KEY" \
     -H "Title: Alert" \
     -d "Sensor triggered!" \
     https://www.iotpush.com/api/push/my-topic

Tip — see real errors instead of silent failures:

curl --fail-with-body -sS \
     -d "Sensor triggered!" \
     https://www.iotpush.com/api/push/my-topic

Language Examples

Python:

import requests
requests.post(
    "https://www.iotpush.com/api/push/my-topic",
    data="Hello from Python!",
    headers={"Title": "Python Alert"}
)

JavaScript / Node.js:

fetch("https://www.iotpush.com/api/push/my-topic", {
  method: "POST",
  body: "Hello from JS!",
  headers: { "Title": "JS Alert" }
});

Arduino / ESP32:

#include <HTTPClient.h>
HTTPClient http;
http.begin("https://www.iotpush.com/api/push/my-topic");
http.addHeader("Title", "ESP32 Alert");
http.POST("Sensor value: " + String(sensorValue));
http.end();

Action Buttons

Add interactive buttons to notifications. Users can respond directly from the notification banner or lock screen — no need to open the app.

Action Object Fields

FieldTypeRequiredDescription
idstringYesUnique identifier for the action (see pre-defined IDs below)
labelstringYesButton text shown to the user
typestringYesbutton · reply · url · dismiss
urlstringNoURL to open (only for type: url)
destructivebooleanNoShow button in red on iOS

Pre-defined Action Categories

Use these specific action id values to enable lock-screen and banner buttons on iOS. The system maps your actions to a pre-registered notification category automatically.

Action IDsButtons Shown
"ack"Acknowledge
"reply" or "comment"Reply (text input)
"ack" + "snooze"Acknowledge, Snooze
"confirm" + "deny"Confirm, Deny
"approve" + "reject"Approve, Reject
"yes" + "no"Yes, No
"open" + "dismiss"Open, Dismiss
"ack" + "snooze" + "reply"Acknowledge, Snooze, Reply
"approve" + "reject" + "comment"Approve, Reject, Comment
"ack" + "escalate" + "reply"Acknowledge, Escalate, Reply

Example — Acknowledge + Snooze + Reply

curl -H "Content-Type: application/json" \
     -H "Authorization: Bearer YOUR_API_KEY" \
     -d '{
  "title": "Server Alert",
  "message": "CPU usage at 95% on prod-01. Acknowledge or snooze?",
  "priority": "high",
  "actions": [
    { "id": "ack",    "label": "Acknowledge", "type": "button" },
    { "id": "snooze", "label": "Snooze 15m",  "type": "button" },
    { "id": "reply",  "label": "Reply",        "type": "reply"  }
  ]
}' \
     https://www.iotpush.com/api/push/my-topic

Example — Approve / Reject workflow

{
  "title": "Deployment Request",
  "message": "Release v2.1.0 to production — requested by @alice",
  "priority": "high",
  "actions": [
    { "id": "approve", "label": "Approve", "type": "button" },
    { "id": "reject",  "label": "Reject",  "type": "button", "destructive": true }
  ],
  "callback_url": "https://your-server.com/deploy-webhook"
}
Note: Action responses are delivered via the Report Action API and/or your callback_url. Use Delivery Receipts to see which actions were taken.

Delivery Receipts

Every notification returns a receipt_id. Use receipts to track delivery, read, and action status.

Get a receipt

GET /api/receipts/{receipt_id}

Auth: Authorization: Bearer USER_SESSION_TOKEN or X-Api-Key: TOPIC_API_KEY

{
  "receipt_id": "b06e8c90-...",
  "message_id": "31d902cf-...",
  "topic_id":   "...",
  "status":     "acted",          // queued · delivered · read · acted · expired · failed
  "delivered_count": 3,
  "read_count":      2,
  "acted_count":     1,
  "actions_taken": [
    {
      "action_id":    "approve",
      "action_label": "Approve",
      "reply_text":   null,
      "device_name":  "Vincent's iPhone",
      "acted_at":     "2026-04-10T00:10:22Z"
    }
  ],
  "created_at": "2026-04-10T00:06:01Z",
  "updated_at": "2026-04-10T00:10:22Z"
}

List receipts

GET /api/receipts

Query Parameters

ParamDescription
topic_idFilter to a single topic
statusqueued · delivered · read · acted · expired · failed
sinceISO 8601 timestamp — only return receipts after this time
cursorPagination cursor (created_at of last item)
limitMax results per page (default 50, max 100)
curl -H "Authorization: Bearer YOUR_SESSION_TOKEN" \
     "https://www.iotpush.com/api/receipts?status=acted&limit=10"

Report Action

Called automatically by the iotpush mobile app when a user taps an action button. You can also call this from your own client to mark an action as taken.

POST /api/action

Auth: Authorization: Bearer USER_SESSION_TOKEN

Request Body

FieldTypeRequiredDescription
message_idstringYesID of the message the action belongs to
action_idstringYesID of the action that was tapped
reply_textstringNoText entered by user for reply-type actions
device_idstringNoDevice ID for attribution
curl -X POST https://www.iotpush.com/api/action \
     -H "Authorization: Bearer USER_SESSION_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
  "message_id": "31d902cf-...",
  "action_id":  "approve",
  "reply_text": null
}'

Webhooks

Receive real-time HTTP callbacks when events occur on your topics — action taken, message delivered, read, or expired. Up to 10 webhooks per account.

Create a webhook

POST /api/webhooks
FieldTypeRequiredDescription
urlstringYesHTTPS endpoint to receive events
eventsstring[]Yesaction · delivered · read · expired · all
topic_idsstring[]NoLimit to specific topics (empty = all topics)
curl -X POST https://www.iotpush.com/api/webhooks \
     -H "Authorization: Bearer USER_SESSION_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
  "url":    "https://your-server.com/hooks/iotpush",
  "events": ["action", "delivered"]
}'

Other webhook endpoints

MethodPathDescription
GET/api/webhooksList all your webhooks
PATCH/api/webhooks/{id}Update url, events, active, or topic_ids
DELETE/api/webhooks/{id}Delete a webhook
POST/api/webhooks/{id}/testSend a test event to the webhook URL

Webhook Payload (action event)

{
  "event":      "action",
  "message_id": "31d902cf-...",
  "topic":      "my-topic",
  "action_id":  "approve",
  "action_label": "Approve",
  "reply_text": null,
  "device_name": "Vincent's iPhone",
  "acted_at":   "2026-04-10T00:10:22Z"
}

Devices

Register and manage push notification devices. The mobile app calls this automatically on login.

Register a device

POST /api/devices
FieldTypeRequiredDescription
push_tokenstringYesExpo push token (ExponentPushToken[...])
platformstringYesios · android · web
device_namestringNoHuman-readable name, e.g. "Vincent's iPhone"
app_versionstringNoApp version string, e.g. "1.1.1"

List devices

GET /api/devices

Returns all registered devices for the authenticated user, sorted by last seen.

Topics API

Programmatically manage your notification topics. All endpoints require a user session token (Authorization: Bearer USER_SESSION_TOKEN).

MethodPathDescription
GET/api/topicsList all your topics
POST/api/topicsCreate a new topic
PATCH/api/topics/{id}Update topic name, description, or privacy
DELETE/api/topics/{id}Delete a topic and all its messages

Create topic body

{
  "name":        "server-alerts",   // required, URL-safe slug
  "description": "Production alerts",
  "is_private":  true               // if true, API key required to push
}

Pushover Compatibility

iotpush provides a Pushover-compatible endpoint. Apps with built-in Pushover support can use iotpush as a drop-in replacement.

POST https://www.iotpush.com/api/1/messages.json

also: POST https://www.iotpush.com/api/pushover

Pushover Paramiotpush Mapping
tokenYour iotpush topic API key
userTopic name (optional if token is unique)
messageNotification message
titleNotification title
urlClick URL
priority-2 to 2 → lowest/low/normal/high/urgent
curl -s \
  --form-string "token=YOUR_TOPIC_API_KEY" \
  --form-string "user=my-topic" \
  --form-string "message=Hello from Pushover-compatible API!" \
  https://www.iotpush.com/api/1/messages.json

To migrate from Pushover: change the API URL from api.pushover.net to www.iotpush.com and use your topic API key as the token.

Rate Limits

PlanMessages/MonthTopics
Free1,0003
Pro ($9/mo)10,00010
Business ($29/mo)100,000Unlimited

Integrations

iotpush works with any automation platform that can make HTTP requests — n8n, Make, Zapier, Home Assistant, and more.

See our full integration guides for step-by-step setup.