Creator Notify v1.0.0

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.

NameRequiredPurpose
VAPID_PUBLIC_KEYyesbase64url 65-byte uncompressed P-256 point. Also served to browsers via /v1/subscriptions/config.
VAPID_PRIVATE_KEYyesbase64url 32-byte scalar used to sign the VAPID JWT.
VAPID_SUBJECTyesmailto: or https: contact; part of the JWT sub claim.
SECRET_PEPPERyesHMAC key for hashing site API keys. Changing it invalidates every key.
SUBSCRIPTION_ENCRYPTION_KEYyesbase64/hex 32 bytes; AES-256-GCM key for push auth secrets. Changing it forces subscribers to re-subscribe.
REGISTRATION_TOKENnoWhen set, POST /v1/sites/register requires x-registration-token.
SWEEP_TOKENnoWhen set, enables POST /v1/internal/sweep.

Settings

NameDefaultRangeEffect
ENVIRONMENTdevelopmentstringEchoed by /health; production suppresses stack traces in logs.
INACTIVITY_DAYS70.0001–365Registration expiry window. Fractions useful in tests.
SYNC_DELIVERY_LIMIT500–1000Audience size above which a publish returns 202 and continues asynchronously.
DELIVERY_PAGE_SIZE1001–500Subscriptions fetched per delivery batch.
DELIVERY_CONCURRENCY81–50Parallel push requests per batch.
DELIVERY_TIMEOUT_MS100001000–30000Per-request timeout to a push service.
MAX_SUBSCRIPTIONS_PER_SITE1000001–10,000,000Hard cap; further subscription attempts return SITE_LIMIT_REACHED.
MAX_PUSH_PAYLOAD_BYTES3500256–3993Serialised JSON payload ceiling.
PUSH_TTL_SECONDS864000–2,419,200Default ttl when a request omits it.
NOTIFICATION_RETENTION_DAYS901–3650Deletes old notifications (attempts cascade).
DELIVERY_ATTEMPT_RETENTION_DAYS301–3650Deletes old delivery attempts.
UNSUBSCRIBED_RETENTION_DAYS301–3650Deletes unsubscribed rows.
RATE_LIMIT_RETENTION_HOURS241–720Deletes expired counters.
RATE_LIMIT_REGISTER_PER_HOUR101–100000Registrations per IP per hour.
RATE_LIMIT_SUBSCRIBE_PER_MINUTE601–100000Subscription calls per minute.
RATE_LIMIT_UNSUBSCRIBE_PER_MINUTE601–100000Unsubscribe calls per minute.
RATE_LIMIT_PUBLISH_PER_MINUTE1201–100000Publishes per site per minute.
RATE_LIMIT_READ_PER_MINUTE3001–100000Read endpoints per site per minute.
REGISTRATION_ATTEMPT_LIMIT41–100Registrations allowed per website address before it is blocked permanently.
REGISTRATION_ENABLEDtruebooleanfalse makes POST /v1/sites/register return REGISTRATION_DISABLED.
ALLOWED_PUSH_HOSTSknown push servicescomma separatedEndpoint host allow-list. Entries starting with . match subdomains. Unset = built-in list.
CORS_ALLOWED_ORIGINS(empty)comma separatedExtra origins allowed on browser-facing routes. Grants no authorization.

Limits that affect your integration

LimitDefaultWhat to do
Payload size3500 bytes of JSON after encodingShorten body, icon, image or data; the hard ceiling of the transport is 3993 bytes.
Publish rate120 per site per minuteBatch your content into one notification rather than many; honour Retry-After.
Subscriptions per account100000Prune dead endpoints; they are invalidated automatically on the first 404/410.
Inline audience50 subscriptionsAbove this a publish returns 202 and finishes in the background; poll the notification for final counts.
Notification history90 daysExport anything you need long-term from GET /v1/notifications.
Inactivity window7 daysPublish 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 when expires_in_seconds drops below two days.
  • Publish responses include warnings; alert on SOME_SUBSCRIPTIONS_WERE_INVALIDATED spikes.
  • 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.