Basics · 01
One message, delivered by Postbox to every phone
Postbox is our own push-notification service. You write the message in the console, choose who it goes to, and Postbox hands it straight to Apple and Google — with a receipt for every device. This manual is for the people who work in the console.
How a message reaches the phone
Who sees what
There are two kinds of accounts that can sign in to the console. A superadmin sees everything. A tenant user (for example, a client company's team) sees only the apps assigned to them — with a separate role on each app:
| What | Viewer | Editor | Superadmin |
|---|---|---|---|
| Dashboard, messages, receipts, audience | read | read | everything |
| Sending, scheduling, cancelling; segments, templates, tags, test devices, permission prompt | — | ✓ | ✓ |
| The app's push keys (Apple, Firebase) | — | ✓ | ✓ |
| Billing — your plan, monthly meter, invoices | read | read | — |
| Audit log | — | for their own apps | everything |
| API keys | — | only if editor on every app | ✓ |
| Users, tenants, plans, new app | — | — | ✓ |
An editor can also be restricted to one segment — for example, in a multilingual app the German colleague can send only to the German segment. They write, send, schedule and edit templates, but can't change anything that decides who a message reaches: segments, audience, keys, the permission prompt, API keys.
Anything you don't have access to doesn't appear in the left-hand menu at all. If you open it through a direct link anyway, you get the Not available to your account page.
Which chapters are for you
Chapters 02–09
Signing in, writing and sending messages, audience, segments, app settings, billing.
Chapter 10
Adding users, assigning apps, password resets, deactivation.
What it deliberately doesn't do
- Mobile push only. No email, SMS, web push or in-app inbox.
- No A/B tests and no automated journeys — every message is started by a person, or by your own backend through the API.
- It doesn't email users either: for new accounts and password resets, the superadmin hands over the temporary password.
Editors and viewers · 02
Your first sign-in starts with a password change
A superadmin creates your account and gives you a temporary password. It lets you sign in once — but until you replace it, the console won't let you do anything else.
Open the console
You get the address and the temporary password from the superadmin — Postbox itself doesn't send emails.
Sign in with your email address
Right after Sign in, the password change screen appears.
Choose your own password
Enter the temporary one in the Current password field, and the new one twice. At least 10 characters, and it can't be the same as the old one.
Save and continue
You'll see the Password changed message, and the Dashboard loads.
Choose your password
You signed in with a password an administrator set. Replace it to continue.
Current password *•••••••••••••••• New password * At least 10 characters••••••••••••• Repeat new password *••••••••••••• Save and continue 1 Sign out 2- Enabled only when the new password is at least 10 characters and both fields match.
- Sign out without changing — the same screen greets you next time you sign in.
Someone else has seen the temporary password: the superadmin, and anyone it passed through on its way to you. So the system won't show you any data until you're the only one who knows your password.
There's no self-service password reset. Ask a superadmin: they'll give you a new temporary password, and you'll have to change it again at your first sign-in.
Editors and viewers · 03
The console always works inside one app
The app you pick in the top-right corner decides what you see on the Compose, Messages, Audience, Segments and Templates pages. Check it before you send anything.
Dashboard
Samplebaby — last 7 days
Weekly digest · tomorrow 09:10 (local time)
Monday tip · sent · 48 910 / 51 002
- App switcher. Lists only the apps assigned to you. Your browser remembers the choice.
- Apple environment. production is the live App Store app; sandbox is the development build. Their tokens aren't interchangeable.
- Poste restante — scheduled messages that haven't gone out yet. One click takes you to the Schedule page.
What the numbers show
| Tile | Meaning |
|---|---|
| Reachable devices | How many phones get notifications right now — this is how many an “everyone” send reaches. The bottom line shows how many have notifications turned off (notifications off), how many are inactive (dead token), and how many are test devices. |
| Messages | Messages accepted in the last 7 days — from the console and the API combined. |
| Delivered | How many devices Apple or Google accepted, out of all receipts. |
| Failed / pruned | Failed deliveries / removed addresses. Pruned isn't an error: the app was deleted from the phone, and Postbox retired the address. |
If someone turned off notifications on their phone, Postbox keeps them but doesn't send to them and doesn't count them as reachable. As soon as they turn notifications back on and next open the app, they're part of the audience again.
The Recent events box only shows rows to editors — audit data is left out of the viewer view.
Editors and viewers · 04
Test devices first, then everyone
The Compose page is three steps from top to bottom: who it goes to, what it says, and when. On the right, a live preview shows how it looks on a phone, with the estimated reach and the send button below it. By default the page targets your test devices — you can only change that on purpose.
New push notification
Sampleapp — write once, send to test devices first.
More targeting options
⊕ Add language 2
TitleHi {{name}}! 3 MessageIn week {{tags.week}} your baby… Launch URLsampleapp://knowledge/week-12 Send to these platforms (2/2) 4› Advanced settings (cross-platform) 5
› Apple iOS settings
› Google Android settings
In week tags.week your baby…
2 devices
Audience: Named test devices
Platforms: iOS + Android
Delivery: Immediately
- Who. The three common modes are visible; one-off filters and specific users are under More targeting options.
- Language variants. Add language asks for a language code (e.g. de) and opens a new tab for German-language phones. The Default tab goes to everyone else; the phone's language decides.
- Placeholders from the recipient's data: {{name}}, {{tags.week}}. If a recipient has no value, it becomes empty text.
- Platforms. You can untick one, so it goes only to iPhones or only to Android phones.
- Rarely needed. Extra data, sound, priority, time to live and the per-platform settings wait collapsed; a section you've filled in shows a 1 set marker in its header.
- Preview. Updates as you type; switch between iOS and Android. Placeholders are highlighted.
- Estimated reach. Recalculates automatically as you change the audience or the platforms.
The text
You can pick a saved template from the Start from template list — it fills in the fields, which you can then edit for this one send; the template itself doesn't change. Or write it here.
| Field | What it's for |
|---|---|
| Title, Message | The notification's title and text. Placeholders: {{name}}, {{tags.week}}. |
| Image | An image in the notification (web address). |
| Launch URL | Where the app opens when tapped, e.g. sampleapp://knowledge/week-12. |
| Send to these platforms | Apple iOS, Google Android, or both. At least one is required. |
Character limits
A live counter runs above the field. It turns orange when the text is longer than a locked screen can show in full; at the hard limit, the field stops accepting input.
| Field | Roughly visible | Maximum |
|---|---|---|
| Title | 50 | 100 |
| Subtitle (iOS) | 50 | 100 |
| Message | 150 | 1000 |
Placeholders count at their written length ({{tags.week}} = 13 characters); the phone shows the substituted value — which may be shorter or longer.
Personalization: the Insert… menu
At the right edge of the Title, Message and Subtitle fields, a + button (Insert…) opens a menu:
Personalization tag
The list shows the tags that actually exist on the app's phones, most common first, with an example value and how many devices have it. It's searchable.
A default value, if needed
In the Default value field, enter what should appear when the recipient doesn't have that data — e.g. there. Left empty, nothing appears.
Insert
It goes in at the cursor, e.g. {{ tags.name | default: "there" }}. You can insert a few common emoji from here too.
In the collapsed sections:
| Section · field | What it's for |
|---|---|
| Advanced · Additional data | Extra data for the app as key–value pairs (Add field), passed through untouched. Fill it in only when the developers ask. |
| Advanced · Collapse id, Sound | Whether a newer notification replaces the older one, and which sound it plays. Left empty, the phone's default applies. |
| Advanced · Priority, Time to live | High is only for urgent, transactional messages; after the TTL, an undelivered notification is dropped. |
| Advanced · Silent push | Nothing appears on the phone; it's for the app only. Only when the developers ask. |
| Apple iOS · Subtitle, Badge | A second line and an icon badge number, iPhone only. |
| Google Android · Notification channel | An Android channel registered by the app. |
Without a default value, missing data becomes empty text, not an error: Hi {{name}}! arrives as Hi ! for a recipient with no name. Add a default in the Insert… menu, or write the text so it works without it.
Who — the Audience
| Mode | Who it goes to |
|---|---|
| Send to named test devices | Only phones marked as test devices. They're listed by name underneath. How to mark one: chapter 06. |
| Send to a segment | A saved segment (chapter 07) — membership is recalculated at send time. |
| Send to everyone | Every active device of the app. An orange warning flags it, and the send button turns orange too. |
| Send to a custom filter (More targeting options) | A one-off filter, not saved. Same editor as for segments. |
| Send to specific users (More targeting options) | Specific users by their own ID, one per line or comma-separated. Goes to all of their phones. |
The selected platforms narrow every mode: if only Apple iOS is active, only the iPhones in a segment get it.
When — the Delivery schedule
| Mode | What it does |
|---|---|
| Immediately | Goes out right away. |
| At a specific time | At a given point in time. |
| At a local time on each device | Reaches each phone at the given time in its own time zone, e.g. 09:10 in Budapest and 09:10 in Berlin. Use the On day (optional) field to pick a specific day. |
| On a recurring schedule | Repeated sending with a Cron expression and a time zone. The default 0 9 * * 1 = every Monday at 9:00, Europe/Budapest. |
If a scheduled time falls within ±2 minutes of the hour, quarter past, half past or quarter to, Postbox moves it slightly. Most of the world's apps send during those minutes, and Google accepts more slowly then. That's why you see a warning about it under Compose, and why 09:10 makes a good default.
Sending, step by step
Pick the app, then write
Check the app switcher in the top right. If you switch apps while writing, Compose takes you back to the Dashboard and the unfinished message is lost — so no segment or template from the other app can linger on screen.
Send it to your test devices
Send to named test devices + Immediately → Send to test devices. Check it on your phone.
Switch the audience
A segment or everyone; check the Estimated reach number on the right.
Send or schedule
Once accepted, the console jumps to the message details (chapter 05).
You can write and count recipients, but the send button is disabled, with this above it: Your role on this app is read-only: you can draft and preview, not send.
Only two audience options remain: test devices, and your own segment (Send to your segment: …). You can't send to everyone, to a filter or to specific users, and you can't cancel other people's messages sent elsewhere.
Editors and viewers · 05
Every phone sends back its own receipt
The Messages page lists all of the app's messages; Schedule lists only the ones that haven't gone out yet. Click a message to see how many phones got it, and what happened with each one.
Weekly digest
immediate · segment · accepted 2026-09-29 09:10
| Subscription | Status | Attempts | Provider id / error |
|---|---|---|---|
| ios · 5f…a91 | sent | 1 | apns-id 8C1E… |
| android · c2…77e | pruned | 1 | UNREGISTERED |
| ios · 0b…3d2 | failed | 1 | BadDeviceToken |
- Cancel is available until the message has finished; for scheduled ones there's also Reschedule next to it. Viewers see neither.
- Receipts per device, filterable by status (any status).
Message statuses
| Status | Meaning |
|---|---|
| scheduled | Waiting for its time — it's on the Schedule page and in the Dashboard's Poste restante box. |
| queued · dispatching · sending | Starting up: Postbox picks the recipients, then sends device by device. |
| sent | An attempt went out to every recipient device. Details are in the receipts. |
| cancelled | Cancelled before it went out. |
| failed | The message as a whole couldn't start. |
Receipt statuses
| Status | Meaning |
|---|---|
| sent | Apple or Google accepted it. |
| queued | Still waiting its turn, or retrying — the Sent / next attempt column shows when. |
| pruned | The address is dead (the app was deleted or reinstalled), so Postbox retired it. It won't even try next time. |
| failed | The provider rejected it, and retrying makes no sense. The reason is in the Provider id / error column. |
| dead_letter | Didn't succeed even after several retries. |
| skipped | No send was needed (e.g. the device was deactivated in the meantime). |
Every old address book is full of addresses from deleted apps. The first big send weeds them out — after that, the pruned count stays small on later sends. Postbox never tries a dead address again.
Editors and viewers · 06
One person, several phones — and yours is a test device
Audience shows the address book in two views: People — users by their own ID, and Devices — individual phones. This is where you mark your own phone as a test device.
Audience
| Device | External id | Locale / tz | Last seen |
|---|---|---|---|
| iOS test | …34cd | hu | today |
| Android | …4f21 | hu | yesterday |
Mark as test device 1
- Give it a recognizable name and press the button. This name appears in Compose under Named test devices. Afterwards, the same place offers Rename and Remove from test devices.
How to find your own phone
Open the app on your phone
At least once, signed in — that's when it registers with Postbox. Allow notifications.
Search for your own ID
In the Devices view, type your external id in the Search field (the developers can tell you which one is yours), or filter by platform and Last seen.
Name it and mark it
In the panel: name → Mark as test device.
A grey muted badge next to a phone means the user turned off notifications on it. Postbox keeps it but won't send to it until they turn them back on.
A phone is only in the address book if the app got a push token from it — that is, if you allowed notifications. With notifications turned off, the device isn't listed and can't be marked as a test device.
People vs. Devices — what's the difference
One user
One external id, with all of their phones. User tags set here apply to all of their phones. Reachable only shows only those who have a live device.
One phone
One push address. Here you see the platform, language, time zone, app version, and when it last checked in.
Filters: Platform, Locale, Tag + Tag value, Last seen (7 / 30 / 90 days, 1 year), Active only, Test devices.
Dead addresses
If Postbox has retired a phone, a red bar sits at the top of the panel: Returned to sender: …. The Reactivate button brings it back, but the address only truly works again once the app checks in from that phone again.
The panel shows all the data, but the save, test-device and deactivate buttons don't appear.
Editors and viewers · 07
A segment is a rule, not a list
A segment describes who gets a message — for example, “German-language phones, from week 12”. It's recalculated at send time, so anyone who has joined since is included. A template is reusable text.
Count devices 182 2 Cancel Save
- Field, operator, value. tag… looks at the phone's tag, user tag… at the user's.
- Count before you save with the Count devices button. On the list page, the Devices now column always shows the current number.
Fields and operators
| Field | Example |
|---|---|
| locale | starts_with de — every German-language phone (de, de-AT, de-CH). |
| platform | eq ios |
| app version | starts_with 1.43 — only people on the new version. |
| last seen, registered | within_days 30 — active in the last 30 days. |
| tag… / user tag… | week gte 12, plan eq pro — whatever the app or you gave the phone or the user. |
| external id, timezone, device model, OS version, is test device | needed less often, but available |
Operators: eq equals, ne not equal, in / nin in / not in the list (a, b, c), gt gte lt lte greater / less than, exists the data is present (true / false), contains, starts_with, within_days.
Many push systems run each language as a separate app. In Postbox there's one app, and we segment by the phone's language (locale starts_with de). The language tabs in Compose (04) solve the same thing within a single send.
locale is the phone's language, not which language version of the app someone used. A German app running on a Hungarian phone counts as Hungarian.
Templates
On the Templates page you fill in the same fields as in Compose, language tabs included. In Compose, picking from the Start from template list fills in the fields. Changes you make there apply only to that one send — you edit the template itself on the Templates page. Template and segment names are unique within an app (A template with this name already exists for the app).
Editors and viewers · 08
Without two keys, not a single notification goes out
Every app needs an Apple key (iPhone) and a Firebase key (Android). An editor uploads them on the Apps page; that's also where you set when the app asks for notification permission.
Apple Developer → Keys → APNs auth key. Not an App Store Connect API key — both are .p8 and they are not interchangeable.
MIGTAgEAMBMGByqGSM49…
-----END PRIVATE KEY-----
Store key 2
- The full file contents, including the BEGIN and END lines.
- Store key (Rotate key for an existing key) validates on save: a wrong key gives you an error right away, not on the first send. To delete: Remove APNs key.
Where the two keys come from
| Tab | Where from | What to paste |
|---|---|---|
| APNs (iPhone) | Apple Developer → Certificates, IDs & Profiles → Keys → “Apple Push Notifications service” | The contents of the .p8, the Key ID and the Team ID. One key works for every app on the team. |
| FCM (Android) | Firebase Console → Project settings → Service accounts → Generate new private key | The full contents of the downloaded JSON (Service account JSON). From the Firebase project the Android app belongs to. |
An Apple account holds several .p8 keys: App Store Connect API, subscriptions (IAP), Sign in with Apple. None of them works for push. If saving says privateKey must be the contents of an APNs auth key, you picked the wrong file.
While either key is missing, a yellow bar on the right side of Compose, above the send button, warns you (only for the selected platforms): APNs credentials are missing — those deliveries will fail until they are stored.
The permission prompt
The app shows its own friendly question before the iOS/Android system permission dialog — because that can only be asked once, and an instant “No” is final. You set its text and rules here, and the app picks them up on its next launch, without releasing a new version.
| Setting | What it means |
|---|---|
| Show this prompt | When off, the app doesn't ask. |
| Title, Body, Allow button, Later button, Image URL | The prompt's text (e.g. Allow / Maybe later), with language variants. |
| Sessions before asking | On which app launch it asks for the first time. |
| Seconds in app | How long into that session before it asks. |
| Cooldown after “later” (days) | After “Maybe later”, it won't ask again for this many days. |
| Max asks, ever | The most times it will ask in total. |
Stats at the bottom: how many times it was shown (shown), and how many people allowed (allowed), postponed (later) or dismissed it (dismissed).
The Credentials and Permission prompt icons are visible only to editors. Only a superadmin can add, rename or disable an app.
Editors and viewers · 09
Some things affect the whole company, not just one app
Three pages belong to the whole tenant rather than to one app: billing, API keys and the audit log. Each has its own permission rule.
Billing — for everyone, read-only
Your plan (Plan), this month's meter (MAU — the number of users active in the month), the expected charge (Projected charge), any open balance (Outstanding), the plan's limits (Limits) and issued invoices as PDFs. You can't change anything here; to switch plans, contact Smartbits.
API keys — only if you're an editor on every app
Keys are how your own backend (sk_…, can send) and the mobile app (pk_…, only registers the phone) reach Postbox. For a new key, the secret is shown once (Copy it now) — after that, only its beginning is visible.
An sk_ key has access to all of the tenant's apps. If an editor of just Samplebaby could create one, they could use it to send to Sampleapp too. So the menu item only appears for someone who is an editor on every app.
Revoke takes effect immediately: anything calling Postbox with that key is rejected from then on. Switch the backend or the app over to the new key first, and only then revoke the old one.
Audit log — who did what, when
Every change is one row: who did it (Actor), what (Action), to what (Target), whether it succeeded (Outcome), and what changed (Changes). Passwords and keys never go into it. Editors see the rows for their own apps; someone who is an editor on every app also sees tenant-level ones (keys, rejected attempts). You can filter by action (message, app.*), by outcome, and with the This app only toggle.
Exporting your data
The Export button on Audience (people and devices), Segments and Templates downloads the current app's data, whole — not just the page or the filter on screen. Anyone who can see the app can export it, viewers too.
- CSV (spreadsheet) — opens in Excel; tags, filters and content sit in one cell as JSON.
- NDJSON (re-importable) — one record per line, exactly as stored; this is the one for the developers.
The device export contains each phone's full push token, which is what lets you move the audience to another service. Treat the file as personal data. Every export is a row in the audit log (Data exported).
For 30 days the console is read-only — a red bar shows the deletion date — but the Export menu keeps working. Save what you need before that date: after it, the data is deleted.
Superadmin · 10
A user belongs to one tenant, with a different role on each app
On the Users page you add console users, assign apps to them, and reset their passwords. Only superadmins see it.
Users
+ New user| User | Access | Status | |
|---|---|---|---|
| admin@example.com | superadmin | active | |
| eva@example.com | Sampleapp Samplebaby · editor Sampleapp · editor | active password pending 1 | 🔐 🔑 ⏻ 2 |
| anna@example.com | Sampleapp Samplebaby · viewer | deactivated | 🔐 🔑 ⏻ |
- Password pending: they haven't signed in yet, or signed in but didn't change the password.
- Row icons: App access, Reset password, Deactivate / Reactivate. You can't deactivate yourself.
Adding a user
New user
Email, name, and the type: Tenant user or Superadmin.
Tenant and apps
For a tenant user, pick the tenant, then set each app to None · Viewer · Editor. For an editor, the Sends only to field restricts them to one segment — left empty, they can send to anyone.
Create
The console generates a temporary password and shows it once (Hand this over now). Copy it.
Hand it over yourself
Postbox doesn't send emails. Share it through a password manager or an encrypted channel — the user replaces it at their first sign-in (chapter 02).
Every tenant, key, push key and invoice. Never give a client superadmin — Tenant user + Editor on every app gives them everything they need.
Changing access
In the App access dialog you set the role per app, and Save replaces the whole set. The change takes effect on the user's next click — they don't need to sign out.
A user can only reach one company's apps at a time; the system won't let you mix apps from two tenants (A user belongs to one tenant). If someone moves to another company, first set all their apps to None, save, and only then pick the new tenant.
An editor restricted to one segment
In a multilingual app, this is how the German colleague gets German-only sending rights: Editor + Sends only to = the German segment. The list shows it on the badge: Sampleapp · editor → German.
If they could rewrite the filter, the restriction would be worthless. So a restricted editor can't change segments, the audience, push keys or the permission prompt, and can't get an API key either (an API key reaches the whole tenant). You, or an unrestricted editor, set the segment's filter.
While someone is restricted to a segment, that segment can't be deleted (An editor is restricted to this segment; change their access first).
Password resets and deactivation
- Reset password — a new temporary password, shown once; the user changes it at their next sign-in.
- Deactivate — the user is signed out on their next click and can't sign in again. Their data and audit log entries are kept; Reactivate brings them back.
Every addition, access change, password change and deactivation goes into the Audit log — the password itself never does.
When things go wrong · 11
The error message usually tells you the cause
The console shows the server's response word for word. Here are the most common ones, with their real causes.
| What you see | What's behind it |
|---|---|
| Not available to your account | Based on your permissions, that menu item isn't yours — a superadmin page, or API keys/audit log that need editor rights. |
| Your role on this app is read-only | You're a viewer on this app. A superadmin can make you an editor. |
| App … not found or … not found for an item you know exists | The item belongs to an app you don't have access to — in that case the system deliberately doesn't reveal that it exists. |
| Account deactivated | A superadmin deactivated your account. |
| Change your password to continue | You're signed in with a temporary password; the password change screen is your next step. |
| Current password is wrong | During the password change, the old (temporary) password didn't match. |
| No test devices named yet — mark some in Audience. | The app has no test devices yet — chapter 06. |
| Estimated reach shows 0 | The filter matches no one, or the app has no live addresses yet. Check the conditions, and that the right app is selected. |
| … credentials are missing | The Apple or Firebase key is missing; phones on that platform get nothing — chapter 08. |
| privateKey must be the contents of an APNs auth key | You uploaded something other than a push key (an App Store Connect / IAP / Sign in with Apple .p8). |
| serviceAccount is missing "…", serviceAccount is not valid JSON | What got pasted wasn't the full contents of the Firebase service-account JSON. |
| Unknown filter field "…", "within_days" only applies to date fields | A mistyped field name, or a date operator on a non-date field. |
| A segment with this name already exists for the app | Names are unique within an app. |
| You may send only to your segment or to the named test devices | You're restricted to one segment; for the audience, choose your own segment or the test devices. |
| You send to one segment of this app; changing its audience or settings is not yours | As a restricted editor, you can't change segments, the audience, keys or the permission prompt. |
| An editor is restricted to this segment; change their access first | Someone is restricted to the segment you want to delete — remove that restriction on the Users page first. |
| The field won't accept more input | You've hit the character limit (Title 100, Message 1000). |
| Fewer devices are “reachable” in Audience than are in the list | The difference is phones with notifications turned off (muted) — they're kept, but don't get messages. |
| Plan limit reached: … | You've hit one of your plan's limits (e.g. number of segments). The Limits section of the Billing page shows them; contact Smartbits to raise them. |
| A recipient got “Hi !” | The placeholder ({{name}}) had no value for that recipient — chapter 04. |
| Lots of pruned after the first send | Not an error: addresses from old, deleted apps. They get cleared out once. |
| I can't find my phone in Audience | Notifications aren't allowed, or the app hasn't yet been opened with a version that registers with Postbox. |
Known limitations
| Limitation | What to do |
|---|---|
| No self-service password reset, and Postbox doesn't send emails | A superadmin gives you a new temporary password. |
| A tenant can't add users on its own | A superadmin adds new colleagues. |
| The plan can't be changed from the console | Ask Smartbits. |
| locale is the phone's language, not the app variant's | If the app variant matters, have the developers give the phone a tag, and segment on that. |