Skip to main content
Scope account:write. A device belongs to whoever is signed into it, which is why it lives under /v1/me with the rest of what an account owns.
Register after signing in, and again whenever the platform hands you a new token — which Apple and Google both do on reinstall, on restore, and occasionally on their own.

Just send it every time

Registering is an upsert, not a create. The app has no durable handle on a registration: it is reinstalled, restored onto a new phone, or simply handed a fresh token, and in none of those cases does it know the id we gave it last time. So the push token decides — the same token updates the row it already owns (200), a new one creates a row (201). You do not have to remember an id, check whether you registered before, or clean up after a reinstall. A token that already belongs to another user is taken over rather than refused. The token addresses a handset, and whoever signed in on it last is who should receive its notifications; leaving it where it was would push the previous owner’s alerts to a phone that is no longer theirs.

The rest

pushToken is write-only and never comes back in a response: the app already has it, and anything else reading it could push to somebody else’s device. It is set only by POST: a PATCH changes appId, appVersion, name, locale, platform or apnsEnvironment, and one carrying pushToken is refused with 422 — a new token is a new registration. GET, PATCH and DELETE reach only your own devices — somebody else’s answers 404, not 403, so the ids cannot be used to count installs. On sign-out, DELETE the registration if you kept the id; otherwise simply stop sending, and it moves along with the token the next time someone signs in on that handset.
Sending is built. Notifications go direct to APNs and FCM — no third-party push service — and every one about the person themselves also lands in the bell at /v1/me/notifications, because a push arrives or it does not and somebody who missed one has no way back to it. A shop’s news does not: see below.The bell, as the website’s inbox has it: filter[unread]=true (or false) narrows the list, PATCH /v1/me/notifications/{id} marks one read, POST /v1/me/notifications/read all of them, DELETE /v1/me/notifications/{id} clears one and DELETE /v1/me/notifications the whole bell — the website’s “delete all”.A registration the platform tells us is dead is deleted on the spot, so a row disappearing during testing is the cleanup working rather than a bug.Send apnsEnvironment with an iOS registration if you can read it (development or production, from the provisioning profile). A simulator build is on Apple’s sandbox and an internal build is on production — Ad Hoc provisioning signs with aps-environment=production however much the build is called “development” — so there is no one setting for us to get right. Without it, the first notification probes: the default is tried, the other host is tried once if Apple refuses the token, and the answer is stored.Send appId with every registration: the bundle id / package of this build (eu.wristler.app, eu.wristler.app.staging or eu.wristler.app.dev). The three apps share one Firebase project, so the token does not say which app it is. A server that is not production pushes only to devices of its own app and logs the rest — a device without appId included — so staging can never reach somebody’s store app. Production pushes to every device.What to do with a push: route on data.type and the ids beside it, never on the words — they are translated, and they come in the language of locale on this registration rather than the language of the account. data.notificationId is the bell entry it belongs to, so opening a push can mark the right item read.

What arrives

Every push carries, in data:
  • type: the category, the switch in the notification preferences that governs it;
  • event: what happened, from the table below — the bell calls the same word event;
  • the ids its screen needs, all strings, and only the ones that event has;
  • notificationId: the bell entry, on everything about the person themselves.
Route on event and the ids; fall back on type for an event you do not know yet, and on the ids for one with no screen of its own. Never on the words.

About the person themselves

These land in the bell as well, and carry notificationId. security and orders pushes cannot be turned off in /v1/me/notification-preferences (labels.{category}.lockedNote says why); saved_searches is set per search (interval, push in /v1/me/saved-searches, and labels.saved_searches.managedPerSearch is true); every other category can, per channel. Locked on is our side only: a phone that refuses notifications still gets no push. Everything still lands in the bell. On the phone, the order ones collapse per order, the saved-watch ones per watch, a saved search’s per search and a thread’s messages per thread (apns-collapse-id / FCM tag): a newer one replaces the older, so the lock screen shows where it ended up rather than every step. The bell keeps every entry. offer_accepted, offer_received and offer_refused may still be on older bell entries; none of them is sent any more.

About a shop somebody works at

Push only, never the bell, so no notificationId. They carry side: "seller" and sellerId: switch into that shop before opening anything. shop_unanswered follows the app plan’s rules: the last message in the thread is the buyer’s, read or not; not an archived thread, not a watch that is sold, offline or deleted, not a thread that led to an order, not a thread the shop marked noReplyNeeded until the buyer writes again, not Wristler’s own aftercare thread, not a thread closed by a block or with a buyer Wristler blocked; one reminder per waiting message, everything waiting in one push, and at most one per shop per 2 hours. Only messages from the last 14 days count. Checked every 15 minutes.

A shop’s news

Somebody who runs a shop can be told when a buyer writes to it, makes it an offer, or pays for one of its watches. That is the shop category in the notification preferences, and it is on unless turned off, like every other category: only people who work at a shop ever receive it. PATCH categories.shop.push to false for somebody who does not want it. Its mail is the digest of what buyers wrote and the “your watch was sold” mail, and is switchable the same way. These pushes carry data.type: "shop", data.side: "seller" and data.sellerId, and either conversationId (a message or an offer, in the shop’s inbox) or orderId (a paid order, in the shop’s orders) — see the table above. Switch into that shop before you open anything: the thread or order belongs to the shop’s side, not to the person’s own. They do not land in the bell, so there is no notificationId.