De documentatie is alleen in het Engels geschreven. De rest van de site is ook in het Nederlands beschikbaar.
Notifications
Every notification the app produces, how it is delivered (in-app, push, e-mail), its wording, and what the user can control.
Bijgewerkt: 29 October 2026
Kinds
| Kind | Trigger | Push title / body (EN) | Tap opens |
|---|---|---|---|
invitation_received | send_invitation | “New invitation” / “Anna wants to connect with you” | 3.1.3 Received invitation |
invitation_accepted | accept_invitation | “Anna accepted” / “You’re now connected” | contact card |
contact_updated | snapshot hash changed for a connection whose circle has notifications on | “Anna updated her details” / “Phone number and address” (changed categories) | contact card, changed rows highlighted |
circle_changed | other party moved you to a circle and your view changed | “Anna changed what you can see” / (no body) | contact card |
system | operator message (rare: policy update requiring acceptance, forced update) | text from the row | in-app dialog |
No notification when a connection ends (A102, 2026-10-29). Removing a contact, blocking, deleting a managed profile and deleting an account used to tell the other side with a contact_removed notification. For privacy they now tell nobody: the card leaves the other person’s list at their next refresh, and their connected services put the entry in the delete bucket as before. The kind is gone from the table above, from notifications.kind, from push and from Settings.
Dutch strings are in the i18n tables; the server picks the language from devices.locale. Bodies never contain the detail values themselves.
Delivery
- A trigger or function inserts a
notificationsrow. - A database webhook calls
push-fanout, which sends one message per row to every device of the account. Coalescing happens where the row is written, not here: while an unreadcontact_updatedorcircle_changedfor the same connection already exists,insert_notificationdrops the new one. A timed batching window on top of that is deferred until there is traffic to measure. - The app, when in the foreground, receives the row through Realtime and updates the bell badge without showing a system banner (Saymail’s rule: no banner for what the user is already looking at).
- In the background the push arrives. Android receives a data-only message (
kind,id) and builds the notification itself in the “Contacts” channel, in the device’s language, then refreshes; iOS receives one alert carryingcontent-available: 1, so the app refreshes before the notification is tapped, withthread-idgrouping the kind andbadgeset to the account’s unread count. - There is no second, silent push: the one message on each platform both shows the notification and wakes the app.
Controls
Settings → Notifications:
- Allow notifications: the OS permission state, read again every time the screen comes back to the front. Three states: on; not asked yet (Android 13 and later, or refused once, when the system dialog may still be shown), with Allow, which shows it and registers this device for push the moment it is granted (A59); and off (refused for good, or switched off in system settings), with Open settings, which opens the app’s own notification page (
Settings.ACTION_APP_NOTIFICATION_SETTINGS). Android cannot say whether it has ever asked, so the app remembers on the device that Settings asked; that flag is a fact about the phone and survives sign-out. - Per kind switches: Invitations (default on, covers
invitation_receivedandinvitation_accepted), Contact updates (default on), Circle changes (default off). They are account columns (notify_invitations,notify_contact_updates,notify_circle_changes, A83;notify_contact_removedis dropped with the kind, A102), so they hold for every device of the account, including one that is off.push-fanoutreads them and skips the push for a kind that is off; the notification row is still written, so the in-app list shows every kind, which the screen says under the switches.systemhas no switch and is always pushed. Each switch is written to the account at once and put back with an error line if the server refuses. - Per circle: managed from the circle’s own switch “Send me updates about people in this circle”.
- Quiet hours are left to the OS (Focus modes / Do Not Disturb); the app does not implement its own.
- E-mail digests: none at launch. Only transactional e-mails exist (sign-in codes, verification codes, e-mail change codes, deletion and export confirmations), each in the account’s language (A92).
In-app list (3.1.5)
Needs you first (round 4, variant 2; mock mobile/design/redesign/redesign-round-5.html). Two sections:
- Needs you: received invitations not yet answered and not ignored, each row “Anna wants to connect”, “2 days ago · says she is your sister”, with Answer and Ignore (Contacts, A103).
- Updates, with “2 new” on the right: everything else, newest first. A contact update says what changed and what happened to it: “Bram · new mobile number”, “Today 09:12 · written to Google” or “Yesterday · waits for sync” (from the connected services’ state for that connection); “Joris accepted”, “Yesterday · in Friends”; “Anna changed what you can see”.
Each avatar carries a small badge for the kind (phone, address, person-add, check). Unread rows are bold with a dot; swipe to mark read; “Mark all read” in the top bar. An ignored invitation does not count towards the bell or the app icon badge. Notifications older than 90 days are pruned server-side. Tapping a notification about a profile that no longer exists shows “This person is no longer on Incico”.
Android specifics
One notification channel “Contacts” (importance default) plus a silent “Sync” channel for the foreground-less background sync status if ever needed. No foreground service, no boot receiver; FCM is the only wake-up (Saymail’s decision).
iOS specifics
UNUserNotificationCenter delegate publishes the tapped notification’s id through the app; the app handles it after the store has loaded. Badge count is set from the unread count on every refresh. Provisional authorisation is not used; the permission is asked in onboarding step 2.4 after an explanation.