Skip to main content

Concepts

Everything in Open Notification is one of six things. Once these are clear, the dashboard, the SDKs and the REST API all read the same way.

App

An app is a tenant. It has a name, a slug, at most one set of credentials per platform (APNs, FCM, Web Push), its own API keys, delivery rules and webhooks. Every user, subscription, campaign and event belongs to exactly one app, and every query the system runs is scoped to one — there is no way for one app's key to read another app's rows.

Typical setups:

  • one app per product (an iOS + Android + web product is one app with three credentials),
  • a second app for staging, so test devices never get production campaigns.

User

A user is a person — the owner of identity and targeting properties:

PropertyMeaning
externalIdYour user id ("user_123"). null while the user is anonymous.
tagsFree-form key → string/number/boolean map. What segments filter on and what placeholders read.
languagePicks which locale of a campaign's content the user receives.
timezoneIANA zone. Drives quiet hours and "send at the user's 19:30".
countryISO 3166-1 alpha-2.

Every device has a user, even before login. A device that subscribes without an externalId gets an anonymous user row. When your app later calls login("user_123"), that anonymous user is renamed — or, if user_123 already exists, the device moves under it. The rules are in Identity.

Subscription

A subscription is one device (or one browser profile): the row that holds the APNs token, the FCM registration token, or the web push endpoint plus its encryption keys. It also carries device facts (platform, appVersion, osVersion, deviceModel, browser, standalone) and a couple of switches:

  • optedInfalse after the user unsubscribes or after 90 days of inactivity. Not targeted.
  • invalidatedAt — stamped when Apple/Google/the push service said the token is dead (410, Unregistered, UNREGISTERED). Not targeted.

A user with a phone and a laptop has two subscriptions. Tags set on the user reach both — the user's properties are copied onto each of their subscription rows so segments, fan-out and personalisation stay one-collection queries.

Campaign

A campaign is one send: content (per locale), a target, a schedule, delivery options, and running counters.

KindHow it startsWhat it looks like
CampaignDashboard wizard or POST /v1/campaigns + /sendNamed, segment-targeted, scheduled, reported on.
TransactionalPOST /v1/notifications from your backendAddressed to specific users/devices, sent immediately. Still gets a campaign row (transactional: true), so it still has a report.

Statuses: draft → scheduled → sending → sent, with cancelled (before fan-out) and failed on the side.

Event

An event is one thing that happened to one push:

TypeWritten byMeaning
sentworkerThe transport accepted it.
failedworkerThe transport rejected it; meta.code says why.
skippedworkerHeld back by a delivery rule; meta.reason is quiet_hours or frequency_cap.
deliveredSDKThe device drew the notification.
openedSDKThe user tapped it.
clickedSDKThe user tapped an action button.
dismissedSDKThe user swiped it away (Android and web only).

Events live in a time-series collection with a 180-day TTL and roll up into the campaign's counters. Rates are computed with delivered as the denominator — see Analytics.

API keys

PrefixNameWhere it livesCan
sk_live_…secret keyyour backend, CIeverything its scopes allow: send, manage users, read reports
pk_live_…public keyapp binary, web pageregister a device; update that device's user

The app id is embedded in the key, so verification is one indexed lookup plus a bcrypt compare. Keys have scopes (notifications:send, campaigns:write, …) and are revocable one at a time from Settings. See API overview for headers and errors.

The dashboard's own login

Dashboard members (owner/admin/editor/viewer) are separate from API keys. They log in with e-mail + password, and the dashboard reaches the API over an internal /v1/admin surface with a shared ADMIN_API_TOKEN that never leaves the server. See Members.