Skip to content

Notifications API

Send a notification to a user's inbox, with optional APNs push delivery to their devices.

Create Notification

POST /notifications

Create an in-app notification and optionally push it to all user devices. Requires an active subscription.

Request Body

FieldTypeRequiredDescription
titlestringYesNotification title
bodystringYesNotification body text
subtitlestringNoOptional subtitle
levelstringNopassive, active (default), or time-sensitive. Controls iOS interruption level.
thread_idstringNoGroups notifications in Notification Center
collapse_idstringNoAPNs deduplication key (max 64 chars). Not stored or returned in responses.
sourcestringNoSource identifier (e.g. integration name)
source_display_namestringNoHuman-readable source name shown in notification settings and inbox grouping
urlstringNoAction URL (max 2048 chars, must start with http:// or https://)
mediaobjectNoRich media attachment. url (HTTPS, max 2048 chars) plus type (image, video, or audio). iOS renders inline. Apple size caps: image 10 MB, audio 5 MB, video 50 MB.
actionsarrayNoUp to 10 dynamic action buttons. Each: id (string, max 64), title (string, max 64), optional url, foreground (bool), destructive (bool), authentication_required (bool), icon (SF Symbol name).
icon_urlstringNoPer-notification source avatar, shown as the Communication Notification avatar on iOS. Accepts http or https (max 2048 chars, recommended ≤256×256 and ≤100 KB; the iOS extension rejects responses larger than 512 KB).
metadataobjectNoKey-value string pairs (max 20 keys, key max 64 chars, value max 4096 chars)
activity_slugstringNoOptional link to an existing activity. An unknown slug is rejected with 422 before the notification is persisted.
pushbooleanNoIf true (default), send APNs rich alert to all user devices. Set false to store in the inbox only.
Info

By default, every notification is delivered as an APNs push to the user's devices. Set push: false to store the notification in the inbox without triggering an alert.

Example
curl -X POST https://api.pushward.app/notifications \
  -H "Authorization: Bearer hlk_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Deploy Complete",
    "body": "Successfully deployed to production",
    "source": "github-actions",
    "source_display_name": "GitHub Actions",
    "level": "active"
  }'

Response (201):

{
  "id": 42,
  "title": "Deploy Complete",
  "subtitle": "",
  "body": "Successfully deployed to production",
  "thread_id": "",
  "level": "active",
  "source": "github-actions",
  "source_display_name": "GitHub Actions",
  "url": "",
  "media_url": "https://example.com/img.png",
  "media_type": "image",
  "actions": [
    { "id": "rerun", "title": "Re-run", "foreground": true }
  ],
  "icon_url": "",
  "metadata": {},
  "activity_slug": "",
  "pushed": true,
  "created_at": "2026-04-24T21:00:00Z",
  "delivery": "all",
  "reason": ""
}

On POST /notifications only, the response also includes two read-only fields describing the APNs fan-out outcome (omitted from GET responses):

FieldValuesMeaning
deliveryall, partial, noneWhether every, some, or no devices accepted the push.
reasonno_apns_token, apns_rejected, push_disabledFailure mode when delivery is not all. Empty on success; omitted entirely when push: false.

Error Responses

Errors follow RFC 9457 Problem Details with Content-Type: application/problem+json. See the canonical Errors section for the body shape and known code values.

StatusMeaning
400Malformed JSON or wrong shape (semantic validation now uses 422)
401Missing or invalid token
403Insufficient permissions or active subscription required (code: subscription.required)
422Unknown activity_slug, or other semantic validation failure
429Rate limit exceeded — pairs with Retry-After and retry_after_ms
500Internal server error