Notifications: identity verification
A publishable key sits in your page’s code, so anyone can copy it. Without a check, anyone holding it could ask for any user_id’s notifications, or mark them read. Identity verification closes that: your server signs the signed-in user’s id, and Launch answers a browser only for the user id it can prove.
How it works
Section titled “How it works”- Create the project’s signing secret once, and keep it on your server.
- When your server renders a page for a signed-in user, it computes
user_hash = HMAC-SHA256(signing secret, user_id)as lowercase hex and hands the page both the user id and the hash. - The page sends
user_idwith every bell call, and the hash in theX-Nordva-User-Hashheader (or auser_hashquery parameter, oruser_hashin the JSON body of the twoPATCHcalls).
Launch computes the same HMAC and compares the two in constant time. A missing or wrong hash answers USER_HASH_INVALID (403). The hash never expires: it is the same for a user id as long as the secret is.
Calls with the secret key from your server need no hash.
Create the signing secret
Section titled “Create the signing secret”From the dashboard, or with the secret key:
curl -X POST https://api.nordva.dev/v1/notifications/signing-secret \ -H "Authorization: Bearer nv_live_YOUR_SECRET_KEY"{ "data": { "signing_secret": "nv_ntf_3f9c...", "created_at": "2026-09-26T10:00:00.000Z", "shown_once": true } }The secret is shown once, in that answer. Save it where your server keeps secrets (for example NORDVA_NOTIFICATIONS_SECRET). Asking again answers SIGNING_SECRET_ALREADY_SHOWN (409). Never put the secret in the browser or in client-side code: with it, anyone could sign any user id.
The HMAC key is the whole secret exactly as shown, nv_ntf_ included.
Compute the hash on your server
Section titled “Compute the hash on your server”Node.js
import { createHmac } from "node:crypto";
export function nordvaUserHash(userId) { return createHmac("sha256", process.env.NORDVA_NOTIFICATIONS_SECRET).update(userId).digest("hex");}Python
import hashlibimport hmacimport os
def nordva_user_hash(user_id: str) -> str: secret = os.environ["NORDVA_NOTIFICATIONS_SECRET"].encode() return hmac.new(secret, user_id.encode(), hashlib.sha256).hexdigest()PHP
<?phpfunction nordva_user_hash(string $userId): string { return hash_hmac('sha256', $userId, getenv('NORDVA_NOTIFICATIONS_SECRET'));}To check your code: with the secret nv_ntf_example_secret and the user id user_123, the hash is 14a440bc09d5207e006d772d46234831782df0b61b49423e8ec8d6665a92811a.
Send it from the page
Section titled “Send it from the page”// userId and userHash came from your server with the pageconst res = await fetch( `https://api.nordva.dev/v1/notifications/inbox?user_id=${encodeURIComponent(userId)}`, { headers: { Authorization: "Bearer nv_pub_live_YOUR_KEY", "X-Nordva-User-Hash": userHash, }, },);const { data } = await res.json();// data.notifications, data.unread_count, data.poll_interval_secondsRotate the secret
Section titled “Rotate the secret”If the secret may have leaked, rotate it:
curl -X POST https://api.nordva.dev/v1/notifications/signing-secret/rotate \ -H "Authorization: Bearer nv_live_YOUR_SECRET_KEY"The new secret is shown once, in the answer. The old one keeps working for 24 hours (previous_valid_until), so you can deploy the new one to your server without the bell failing in between. After that only the new one verifies.
Projects that had notifications before 26 Sep 2026
Section titled “Projects that had notifications before 26 Sep 2026”Before this check existed there was no way to send a hash, so a project that already held notifications keeps working as before: require_user_hash is off, and GET /v1/notifications/unread and PATCH /v1/notifications/{id}/read still answer a browser without a hash. Those answers carry meta.identity_verification: "off" with a warning, and GET /v1/setup-check and GET /v1/notifications/settings warn too. The newer bell endpoints (inbox, unread/count, read-all) always need the hash.
While it is off, anyone with your publishable key can read any user’s notifications. To switch it on:
- Create the signing secret and add the hash to your pages as above.
- Check a page works with the hash sent.
- Switch the check on:
curl -X PATCH https://api.nordva.dev/v1/notifications/settings \ -H "Authorization: Bearer nv_live_YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "require_user_hash": true }'Every other project has the check on from the start.