Skip to content

Results and limits / Statuses

Statuses

What each attempt status means, what the browser reports back, and why accepted is not the same as seen.

Every notification creates one attempt per connected browser, and each attempt has its own status. There is no delivered status, because no browser vendor's push service reports delivery to a screen.

Warningaccepted means the push service took the message. It does not mean the notification was displayed: the device may be off, offline past the TTL, muted or in Do Not Disturb.

Attempt statuses#

StatusFinalMeaning
queuednot yetCreated and waiting for the sender, or waiting again after a retryable answer: a network failure, a timeout, 429, 5xx or any other status that is not an acceptance, 404/410 or 400/403/413.
processingnot yetBeing sent to the push service right now. A sender holds it for 60 seconds; if the sender stops, the attempt is picked up again.
acceptedfinalThe push service accepted the message for that browser. With a test key the attempt is set to accepted the moment it is created, and nothing is sent.
failedfinalThe push service rejected the message for good (400, 403 or 413), the last of the 6 tries of a send job got a retryable answer, or the request could not be built.
expiredfinalThe TTL passed before Push could hand the message over, or its content had already been removed. A ttl of 0 gets 300 seconds.
invalid_subscriptionfinalThe push service answered 404 or 410 (the browser is gone), or the browser was disconnected before sending. The browser is disconnected, and for a live send the attempt is removed from the month's count.

Events reported by the browser#

Push's service worker reports what the person does with a notification. These fields are certain when present, and only the first event of each kind is kept.

FieldMeaning
clickedAtWhen the person first clicked the notification or one of its action buttons.
actionClickedThe id of the action button behind that first click, or null for a click on the notification itself. See actions.
closedAtWhen the person first dismissed the notification without clicking it.
NoteAn event is recorded only if it reaches Push. A missing clickedAt does not prove nobody looked: the person may have read it and moved on, or the browser may have been offline.

Lifecycle#

⫻

lifecycle

queued ──▶ processing ──▶ accepted   ▲            │        ├─▶ failed   └── retry ◀──┘        ├─▶ expired                         └─▶ invalid_subscription
  • Every live attempt starts as queued, moves to processing when a sender picks it up, and ends in exactly one final status.
  • A retryable answer sends a processing attempt back to queued for another try, up to 6 tries per send job with growing waits. An attempt stuck for more than 15 minutes is queued again by the hourly cleanup with a fresh budget, until its TTL runs out. See what happens next.
  • A final status never changes again. Clicks and dismissals are added on top of accepted attempts.

Reading statuses#

Read a notification and all its attempts with its id:

⫻

curl

curl https://api.meslzy.com/push/v1/notifications/0199b1c2-7a4e-7c3d-9f1e-2b6a8d4c5e10 \  -H "Authorization: Bearer $PUSH_API_KEY"

⫻

200 OK

HTTP/1.1 200 OKContent-Type: application/jsonX-Request-Id: req_0199b1c27a4e7c3d9f1e2b6a8d4c5e11
{  "id": "0199b1c2-7a4e-7c3d-9f1e-2b6a8d4c5e10",  "recipient": "ops",  "mode": "live",  "createdAt": "2026-10-05T09:12:44.120Z",  "attemptCount": 2,  "attempts": [    {      "id": "0199b1c2-7a52-7aa0-8c11-5d0e4f3b2a91",      "browser": {        "id": "0198f0aa-1c2d-7e3f-9a4b-5c6d7e8f9012",        "label": "Chrome on Windows"      },      "status": "accepted",      "tries": 1,      "acceptedAt": "2026-10-05T09:12:44.610Z",      "clickedAt": "2026-10-05T09:13:02.004Z",      "closedAt": null,      "actionClicked": "open"    },    {      "id": "0199b1c2-7a53-7b11-9d22-6e1f5a4c3b02",      "browser": {        "id": "0198f0ab-2d3e-7f40-8b5c-6d7e8f901234",        "label": "Safari on iPhone"      },      "status": "invalid_subscription",      "tries": 1,      "acceptedAt": null,      "clickedAt": null,      "closedAt": null,      "actionClicked": null    }  ]}
  • Most attempts settle within seconds. If you poll, a few seconds apart is enough, and stop once every attempt has a final status.
  • Polling counts toward your rate limits.
  • The dashboard shows the same attempts for each notification, with the last error the push service returned.