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-Type✅application/json
Token✅Your API key
Authorization✅Bearer <jwt-token>

* One of Token or Authorization is required

Body Parameters ​

ParameterTypeRequiredDescription
titlestring✅Notification title
messagestring✅Notification body text
application_idstring❌Application TID to categorize the message
device_idstring❌Specific device TID, omit for all devices
levelstring | int❌Priority 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.
actionsarray❌Up to 3 action buttons shown on the notification. See Action buttons.
send_atstring | int❌Deliver at a specific time instead of immediately. RFC3339, Unix timestamp, or YYYY-MM-DD HH:MM. See Scheduled delivery.
delaystring❌Deliver 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
typestring✅view (open a URL), http (fire an HTTP request), or copy (copy text to clipboard)
labelstring✅Button text. Shown on Android; on iOS a generic label per type is shown (Open / Run / Copy)
valuestring✅Depends 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"
}

Quota Headers ​

Responses carry today's daily limit usage (omitted on unlimited plans):

HeaderDescription
X-PA-Daily-LimitMessages allowed per day on your plan
X-PA-Daily-RemainingMessages left today, after this one
X-PA-Daily-ResetUnix timestamp (seconds) of the next reset, 00:00 UTC

Error Responses ​

StatusDescription
401Unauthorized — Invalid or missing token
422Validation Error — Missing required fields
429Daily limit reached — the message was not stored or sent. Wait for Retry-After seconds or upgrade. See Daily message limits.
json
{
  "error": "Validation failed",
  "details": {
    "title": ["The title field is required"]
  }
}

Daily limit reached ​

When today's quota is used up, the message is rejected — not queued — until 00:00 UTC. Retry-After holds the seconds left until the reset.

http
HTTP/1.1 429 Too Many Requests
Retry-After: 30142
X-PA-Daily-Limit: 50
X-PA-Daily-Remaining: 0
X-PA-Daily-Reset: 1790035200
json
{
  "error": "Daily message limit reached (50/50). New messages are rejected until 00:00 UTC. Upgrade your plan to raise the limit.",
  "limit": 50,
  "used": 50,
  "resets_at": "2026-09-22T00:00:00Z",
  "upgrade_url": "https://pocketalert.app/pricing"
}

Deleting messages does not free up quota. Check today's usage with GET /v1/messages/usage.

Pocket Alert Documentation