Skip to main content
20% off 3 months · code LAUNCH20 · until 31 October

Send in-app notifications from Python

No queue to run. Send a notification to one user id or to everyone from your server or an agent, and show it in a bell that one script tag adds to your app, or read it through the API and draw your own.

Keys

Sending uses a secret key on your server, which also signs each user id with the notifications signing secret. The browser reads with a publishable key and that signature. Create both under Dashboard → API keys.

Publishable key pasted into the page that embeds the form
NORDVA_SECRET_KEY=nv_live_…

01Server: Python

notify.py

import os
import httpx

res = httpx.post(
    "https://api.nordva.dev/v1/notifications",
    headers={"Authorization": f"Bearer {os.environ['NORDVA_SECRET_KEY']}"},
    json={"user_id": user_id, "title": "Export ready", "body": "Your CSV is ready to download.", "action_url": "https://app.example.com/exports", "icon": "check"},
)
if res.status_code >= 400:
    err = res.json()["error"]
    raise RuntimeError(f"{err['code']}: {err['message']}")
data = res.json()["data"]
print(data["id"])

Every plan, per project per month: Free 1,000, Indie 20,000, Builder 200,000. Past that the API answers PLAN_LIMIT_REACHED. To post to everyone, send audience: "all" instead of user_id.

02Server: sign the user id (signing secret, never in the browser)

import hashlib, hmac, os

def user_hash(user_id: str) -> str:
    secret = os.environ["NORDVA_NOTIFICATIONS_SECRET"].encode()
    return hmac.new(secret, user_id.encode(), hashlib.sha256).hexdigest()

Create the signing secret once, with POST /v1/notifications/signing-secret and a secret key or through the MCP server. It is shown once: store it as NORDVA_NOTIFICATIONS_SECRET on your server.

03Verify from a terminal

curl -s "https://api.nordva.dev/v1/notifications/unread?user_id=user_123" \
  -H "Authorization: Bearer nv_live_…" | jq '.data.notifications | length'

Behaviour worth knowing

  • Every response is { data, error, meta }. On failure error.code is a stable string such as VALIDATION_ERROR, PLAN_LIMIT_REACHED or RATE_LIMITED, with a remediation message.
  • POST and PATCH requests accept an Idempotency-Key header; the same key with the same body returns the original response for 24 hours.
  • Rate limits per key: 30 requests a minute on Free, 120 on Indie, 500 on Builder. A 429 carries Retry-After.
  • Browser calls with a publishable key must come from an origin registered on the project, otherwise the API answers ORIGIN_NOT_ALLOWED.