Settings & limits
What an operator can tune on an instance of this API, and what that means for the account calling it. Defaults are
the values in src/config.js.
Using a hosted instance?
You do not need to change anything below: your account already has sensible defaults. The tables are here so you know the ceilings you are working within — payload size, rate limits, retention — and so a self-hoster can tune them.
Server-side secrets
Set by whoever operates the instance. Never sent to a browser, never returned by any endpoint.
| Name | Required | Purpose |
|---|---|---|
VAPID_PUBLIC_KEY | yes | base64url 65-byte uncompressed P-256 point. Also served to browsers via /v1/subscriptions/config. |
VAPID_PRIVATE_KEY | yes | base64url 32-byte scalar used to sign the VAPID JWT. |
VAPID_SUBJECT | yes | mailto: or https: contact; part of the JWT sub claim. |
SECRET_PEPPER | yes | HMAC key for hashing site API keys. Changing it invalidates every key. |
SUBSCRIPTION_ENCRYPTION_KEY | yes | base64/hex 32 bytes; AES-256-GCM key for push auth secrets. Changing it forces subscribers to re-subscribe. |
REGISTRATION_TOKEN | no | When set, POST /v1/sites/register requires x-registration-token. |
SWEEP_TOKEN | no | When set, enables POST /v1/internal/sweep. |
Settings
| Name | Default | Range | Effect |
|---|---|---|---|
ENVIRONMENT | development | string | Echoed by /health; production suppresses stack traces in logs. |
INACTIVITY_DAYS | 7 | 0.0001–365 | Registration expiry window. Fractions useful in tests. |
SYNC_DELIVERY_LIMIT | 50 | 0–1000 | Audience size above which a publish returns 202 and continues asynchronously. |
DELIVERY_PAGE_SIZE | 100 | 1–500 | Subscriptions fetched per delivery batch. |
DELIVERY_CONCURRENCY | 8 | 1–50 | Parallel push requests per batch. |
DELIVERY_TIMEOUT_MS | 10000 | 1000–30000 | Per-request timeout to a push service. |
MAX_SUBSCRIPTIONS_PER_SITE | 100000 | 1–10,000,000 | Hard cap; further subscription attempts return SITE_LIMIT_REACHED. |
MAX_PUSH_PAYLOAD_BYTES | 3500 | 256–3993 | Serialised JSON payload ceiling. |
PUSH_TTL_SECONDS | 86400 | 0–2,419,200 | Default ttl when a request omits it. |
NOTIFICATION_RETENTION_DAYS | 90 | 1–3650 | Deletes old notifications (attempts cascade). |
DELIVERY_ATTEMPT_RETENTION_DAYS | 30 | 1–3650 | Deletes old delivery attempts. |
UNSUBSCRIBED_RETENTION_DAYS | 30 | 1–3650 | Deletes unsubscribed rows. |
RATE_LIMIT_RETENTION_HOURS | 24 | 1–720 | Deletes expired counters. |
RATE_LIMIT_REGISTER_PER_HOUR | 10 | 1–100000 | Registrations per IP per hour. |
RATE_LIMIT_SUBSCRIBE_PER_MINUTE | 60 | 1–100000 | Subscription calls per minute. |
RATE_LIMIT_UNSUBSCRIBE_PER_MINUTE | 60 | 1–100000 | Unsubscribe calls per minute. |
RATE_LIMIT_PUBLISH_PER_MINUTE | 120 | 1–100000 | Publishes per site per minute. |
RATE_LIMIT_READ_PER_MINUTE | 300 | 1–100000 | Read endpoints per site per minute. |
REGISTRATION_ATTEMPT_LIMIT | 4 | 1–100 | Registrations allowed per website address before it is blocked permanently. |
REGISTRATION_ENABLED | true | boolean | false makes POST /v1/sites/register return REGISTRATION_DISABLED. |
ALLOWED_PUSH_HOSTS | known push services | comma separated | Endpoint host allow-list. Entries starting with . match subdomains. Unset = built-in list. |
CORS_ALLOWED_ORIGINS | (empty) | comma separated | Extra origins allowed on browser-facing routes. Grants no authorization. |
Limits that affect your integration
| Limit | Default | What to do |
|---|---|---|
| Payload size | 3500 bytes of JSON after encoding | Shorten body, icon, image or data; the hard ceiling of the transport is 3993 bytes. |
| Publish rate | 120 per site per minute | Batch your content into one notification rather than many; honour Retry-After. |
| Subscriptions per account | 100000 | Prune dead endpoints; they are invalidated automatically on the first 404/410. |
| Inline audience | 50 subscriptions | Above this a publish returns 202 and finishes in the background; poll the notification for final counts. |
| Notification history | 90 days | Export anything you need long-term from GET /v1/notifications. |
| Inactivity window | 7 days | Publish at least weekly, or call POST /v1/sites/reactivate. |
Monitoring
GET /health— 200/503 with a database probe. Point your uptime monitor here.- /status — the same probe, plus your account lifecycle and delivery history, drawn as a page.
GET /v1/sites/status— lifecycle and counters; alert whenexpires_in_secondsdrops below two days.- Publish responses include
warnings; alert onSOME_SUBSCRIPTIONS_WERE_INVALIDATEDspikes. - Every error response carries
x-request-id; it is the only reliable way to correlate a report with a log line.
FAQ
Where is the dashboard?
There isn't one, by design. Your admin panel is the dashboard: call GET /v1/sites/status and
GET /v1/notifications from the place where you already work. The registration
page and the demo cover the one-off tasks.
Why two keys, and which one goes where?
The public key (pub_…) identifies your site to a browser and can only collect subscriptions. The secret
key (cn_live_…) authorises sending and belongs on your server. See Your
API keys.
Can different websites on the same instance interfere?
No. Every authenticated query is scoped by the site id derived from the secret key, and no endpoint accepts a
caller-supplied site id for writes. A test in tests/tenant-isolation.test.js exercises exactly this.
Why did my notification return 202?
The audience exceeded SYNC_DELIVERY_LIMIT. Delivery continues in the background. Poll
GET /v1/notifications/:id for the final counts.
Do notifications survive a user being offline?
Usually yes, within the ttl you set (24 hours by default): the push service stores the message and
delivers it when the device reconnects. After the TTL expires the push service discards it. This is the push
standard, not something Creator Notify controls.
Can I self-host it?
Yes — the API is MIT licensed and self-hostable. Operator instructions live in the repository README; everything in these docs applies unchanged, with your own host as the base URL.
What does it cost?
That depends on the instance you are calling and on how much you send. Push delivery itself is performed by the browsers' push services and is free; hosting, database reads/writes and retained history are what scale with usage. No quota on this page is described as unlimited, because none is.