Skip to content

Create Message POST

Send a push notification to your devices.

Endpoint

POST https://api.pocketalert.app/v1/messages

Authentication

Required

Include one of these headers in your request:

  • Token: <your-api-key> — Get it from API Keys
  • Authorization: Bearer <jwt-token> — From Login

Request

Headers

HeaderRequiredDescription
Content-Typeapplication/json
TokenYour API key
AuthorizationBearer <jwt-token>

* One of Token or Authorization is required

Body Parameters

ParameterTypeRequiredDescription
titlestringNotification title
messagestringNotification body text
application_idstringApplication TID to categorize the message
device_idstringSpecific device TID, omit for all devices
levelstring | intPriority level controlling how the push is delivered. Accepts a name or an int (-2..2). priority is accepted as a synonym. Defaults to the application's default level, then default.
actionsarrayUp to 3 action buttons shown on the notification. See Action buttons.
send_atstring | intDeliver at a specific time instead of immediately. RFC3339, Unix timestamp, or YYYY-MM-DD HH:MM. See Scheduled delivery.
delaystringDeliver after a relative delay — 30m, 2h, or bare seconds. Mutually exclusive with send_at.

Action buttons

Each notification can carry up to 3 action buttons. actions is an array of objects:

FieldTypeRequiredDescription
typestringview (open a URL), http (fire an HTTP request), or copy (copy text to clipboard)
labelstringButton text. Shown on Android; on iOS a generic label per type is shown (Open / Run / Copy)
valuestringDepends on type — see below

value by type:

  • view — the URL to open, e.g. "https://pocketalert.app".
  • http — a JSON string describing the request: {"url":"https://…","method":"POST","headers":{…},"body":"…"}. Only url is required; method defaults to GET. Fires silently in the background without opening the app.
  • copy — the literal text placed on the clipboard.

Human-in-the-loop

Two http actions (e.g. Approve / Decline) make a one-tap control panel — ideal for approving LLM-agent actions straight from the notification.

See Action buttons for limits, validation and webhook templates.

Priority levels

LevelAliasesBehavior
silentmin, -2Delivered to the tray only — no sound or vibration
low-1Quiet, no interruption
defaultnormal, 0 (or omitted)Standard banner + sound
high1Time-sensitive — breaks through Focus / scheduled summary
criticalmax, urgent, 2Wakes the device through the silent switch and Do Not Disturb

WARNING

critical is a paid-plan feature. On free plans it is automatically downgraded to high. Invalid values (unknown name or out-of-range int) return 400.

See Priority levels for how each level behaves on iOS and Android.

Scheduled delivery

Add send_at or delay — never both — and the message is stored encrypted until its delivery time instead of being sent immediately.

ParameterAcceptsExamples
send_atRFC3339, Unix timestamp, or YYYY-MM-DD HH:MM2026-08-15T09:00:00Z, 1786867200
delayGo-style duration or bare seconds30m, 2h, 3600

A time without an offset is read in your account timezone. The horizon is 30 days, and a past send_at returns 400 (with 60 seconds of tolerance for clock skew).

Scheduled requests return 201 with "scheduled": true, status, deliver_at and deliver_at_utc instead of a delivered message. List them with GET /v1/messages/scheduled and cancel with DELETE /v1/messages/scheduled/{tid} — see Scheduled delivery.

WARNING

Scheduled delivery is a paid-plan feature. Free-plan requests using send_at or delay return 403.

Example Request

bash
curl -X POST "https://api.pocketalert.app/v1/messages" \
  -H "Token: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Server Alert",
    "message": "CPU usage exceeded 90%",
    "application_id": "qm47b9pzxzxg",
    "level": "critical",
    "actions": [
      { "type": "view", "label": "Dashboard", "value": "https://status.example.com" },
      { "type": "http", "label": "Restart", "value": "{\"url\":\"https://ops.example.com/restart\",\"method\":\"POST\"}" },
      { "type": "copy", "label": "Copy ID", "value": "incident-4821" }
    ]
  }'
javascript
const response = await fetch('https://api.pocketalert.app/v1/messages', {
  method: 'POST',
  headers: {
    'Token': 'your-api-key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'Server Alert',
    message: 'CPU usage exceeded 90%',
    application_id: 'qm47b9pzxzxg'
  })
});

const data = await response.json();
console.log(data);
python
import requests

response = requests.post(
    'https://api.pocketalert.app/v1/messages',
    headers={
        'Token': 'your-api-key',
        'Content-Type': 'application/json'
    },
    json={
        'title': 'Server Alert',
        'message': 'CPU usage exceeded 90%',
        'application_id': 'qm47b9pzxzxg'
    }
)

print(response.json())
php
$response = Http::withHeaders([
    'Token' => 'your-api-key',
])->post('https://api.pocketalert.app/v1/messages', [
    'title' => 'Server Alert',
    'message' => 'CPU usage exceeded 90%',
    'application_id' => 'qm47b9pzxzxg',
]);

return $response->json();

Response

Success Response

201 Created

Message created successfully

FieldTypeDescription
tidstringUnique message identifier
titlestringMessage title
messagestringMessage body
applicationstringApplication name (if specified)
devicestringTarget device name
actionsarrayAction buttons echoed back (only when provided)
created_atstringCreation timestamp
json
{
  "tid": "jb4xw9elz28g",
  "title": "Server Alert",
  "message": "CPU usage exceeded 90%",
  "application": "Monitoring",
  "device": "iPhone",
  "actions": [
    { "type": "view", "label": "Dashboard", "value": "https://status.example.com" }
  ],
  "created_at": "18.01.2026 15:35:35"
}

Error Responses

StatusDescription
401Unauthorized — Invalid or missing token
422Validation Error — Missing required fields
429Rate Limited — Too many requests
json
{
  "error": "Validation failed",
  "details": {
    "title": ["The title field is required"]
  }
}

Pocket Alert Documentation