API concepts
Base URL: https://api.litepush.dev. All endpoints accept and return JSON unless otherwise stated.
This section is a reference, not a tutorial. If you're integrating for the first time, start with Getting started instead. Each endpoint path has its own page in the sidebar — this page covers the shared concepts they all build on.
Glossary
Quick glossary so the field names across the endpoint pages make sense.
| Term | What it is | Where it comes from |
|---|---|---|
| Project | A namespace that owns subscribers, broadcasts, groups, and keys. One project per site/app you push to. | You create it in the dashboard. |
| Project ID | Public identifier — looks like prj_01HXM.... Safe to expose in browser code. | Dashboard → Project overview. |
| API key | Secret server-to-server token — looks like lpk_live_*. Shown once at project creation; we only store its SHA-256 hash. | Dashboard → Project overview (or rotate via Settings). |
| VAPID public key | Public half of the keypair used to sign push messages. Safe to embed in your <script> tag. Rotating the keypair (Settings → Rotate VAPID keys) invalidates every active subscription — subscribers must re-opt in with the new key. | Generated automatically per project. |
| Subscriber | One browser that opted in to your project's pushes. Identified internally by sub_*. | Created when the SDK calls POST /v1/subscribe. |
| Endpoint URL | The push gateway URL the browser handed back when the user opted in (FCM / Mozilla / Apple). Stable per browser install. | PushSubscription.endpoint from the Web Push API. |
| p256dh / auth keys | Encryption material from the browser's PushSubscription. Required to encrypt the push payload. | PushSubscription.getKey('p256dh') / getKey('auth'). |
| external_id | Your own user ID, optionally attached to a subscriber. Lets you target one user across multiple devices. | Your application. |
| Broadcast | One send operation — fan-out to all/group/user subscribers. Identified by bdc_*. | Created by POST /v1/send or the dashboard's broadcast form. |
| Group | A named segment within a project. A subscriber can be in any number of groups. Identified by grp_*. | Created via dashboard or POST /v1/groups. |
Authentication
LitePush uses two auth styles depending on whether the caller is your server or a browser.
Server-to-server — Bearer token
Server endpoints (anything you call from your backend) require your API key in the Authorization header:
Authorization: Bearer lpk_live_xxxxxxxx
Endpoints requiring Bearer auth: GET /v1/me, POST /v1/send, all /v1/broadcasts* (read, list, cancel), all /v1/groups/*, all /v1/subscribers/*.
A missing, malformed, or revoked key returns 401 invalid_api_key.
Browser — Project query parameter
Three endpoints are called from a browser (the SDK and the service worker): /v1/subscribe, /v1/unsubscribe, /v1/events. These can't carry your secret API key — anyone would see it in DevTools — so they identify the project by its public ID instead:
?project=prj_xxxxxxxx
Or as a header (the SDK uses the header automatically):
X-LitePush-Project: prj_xxxxxxxx
http://localhost origins are not accepted by the API. If you're developing against the endpoint, tunnel your dev server through Cloudflare Tunnel or ngrok and register the tunnel's HTTPS hostname as your project's origin.
Project IDs are public by design — they ship in your client-side <script> tag and are visible in DevTools, like a publishable key, and that's fine: they're meant to be public. The only real secret is your API key (the lpk_live_… Bearer token) — keep that server-side, and rotate it from the dashboard if it ever leaks.
If you have a use case for server-side authoritative subscribe (seeding subscribers from your backend rather than from a real browser) — there isn't a Bearer-authed equivalent of /v1/subscribe today. Email support@litepush.dev and tell us your shape.
Quick reference
| Method | Path | Auth | Purpose |
|---|---|---|---|
POST | /v1/subscribe | Project | Register a browser's push subscription |
POST | /v1/unsubscribe | Project | Soft-unsubscribe a browser |
POST | /v1/events | Project | Service-worker click/dismiss beacon (SDK-internal) |
GET | /v1/me | Bearer | Verify your API key, get project identity |
POST | /v1/send | Bearer | Trigger a broadcast (immediate, or scheduled via scheduled_at) |
GET | /v1/broadcasts | Bearer | List the project's broadcasts (paginated) |
GET | /v1/broadcasts/:id | Bearer | Read one broadcast — status + delivered/failed counts |
DELETE | /v1/broadcasts/:id | Bearer | Cancel a not-yet-fired scheduled broadcast |
GET | /v1/groups | Bearer | List groups in this project |
POST | /v1/groups | Bearer | Create a group |
PATCH | /v1/groups/:id | Bearer | Rename a group or edit its description |
DELETE | /v1/groups/:id | Bearer | Delete a group (memberships cascade, subscribers stay) |
POST | /v1/groups/:id/subscribers | Bearer | Add subscribers to a group |
DELETE | /v1/groups/:id/subscribers/:sid | Bearer | Remove a subscriber from a group |
DELETE | /v1/subscribers/by-endpoint | Bearer | GDPR erasure by push endpoint URL |
DELETE | /v1/subscribers/by-external-id/:eid | Bearer | GDPR erasure by external_id |
GET | /v1/subscribers/export | Bearer | GDPR portability — download CSV |
GET | /health | None | Service health probe |
Error format
Every error response uses the same envelope so your code can branch on error.code:
{
"error": {
"code": "monthly_push_limit_reached",
"message": "Project would exceed the hobby plan cap of 200,000 pushes/month. This broadcast would add ~5,000."
}
}
codeis a stable machine-parsable identifier. Treat it as your contract.messageis human-readable and may change between releases. Show it in dashboards / debug pages, but don't string-match it in code.
Rate limits
Each project is capped at 600 requests/minute across all /v1/* endpoints.
On overage you get:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{ "error": { "code": "rate_limited", "message": "Project is over its per-minute API quota." } }
If you're consistently hitting this, you're almost certainly fan-outing from client-side code that should be batched into a server-side cron — email support@litepush.dev and we'll help architect a fix.
Status codes used
| Code | Meaning |
|---|---|
200 | OK |
201 | Created (subscribe, group create) |
202 | Accepted (send, events beacon) — work continues async |
400 | Bad request — invalid body, missing required param |
401 | Auth failure — missing / invalid Bearer token |
403 | Plan-cap or permission failure (see error.code) |
404 | Resource not found (project, group, etc.) |
409 | Conflict (e.g. group name taken) |
429 | Rate limited |
5xx | Server-side issue — please retry with exponential backoff |