Notifications
Aldero Notifications is a multi-tenant delivery service for email, push, and SMS. You render messages from templates, send them to a user or address, and track delivery — all through one REST API.
Tenant & environment model
Every tenant has two isolated environments: production and sandbox. Templates, devices, push credentials, and API keys are scoped to a tenant + environment.
The service resolves the tenant from the request subdomain — {slug}.notify.aldero.io for production, {slug}-sandbox.notify.aldero.io for sandbox. For server-to-server calls you can skip the subdomain and send headers instead:
Authorization: Bearer ntf_live_xxxxxxxxxxxx
X-Tenant-Slug: myapp
X-Tenant-Env: production # defaults to productionGetting API keys
Keys come in two kinds, both scoped to one environment:
- Secret key (
ntf_prefixed) — full server-side access. Keep it on your backend. - Publishable key (
pk_prefixed) — restricted to device registration only (POST /v1/devices,DELETE /v1/devices/{token}). Safe to embed in mobile/web clients.
An owner or admin creates keys. The raw key is returned once and cannot be retrieved again.
curl -X POST https://myapp.notify.aldero.io/v1/keys \
-H "Authorization: Bearer ${MASTER_OR_JWT}" \
-H "Content-Type: application/json" \
-d '{"environment": "production", "kind": "secret"}'
# → { "key": "ntf_live_...", "kind": "secret", "environment": "production", "prefix": "ntf_live", "createdAt": "..." }Rotate a leaked key with POST /v1/keys/{environment}/rotate (secret) or /rotate-publishable.
Send a notification
POST /v1/notifications/send renders a template by name and queues delivery. The response is 202 with a notificationId you can track.
to is a user ID for push (looked up against registered devices) or an email address / phone number for email and SMS.
# Email
curl -X POST https://myapp.notify.aldero.io/v1/notifications/send \
-H "Authorization: Bearer ${NTF_SECRET_KEY}" \
-H "Content-Type: application/json" \
-d '{
"templateName": "welcome-email",
"channel": "email",
"to": "user@example.com",
"variables": { "name": "John" }
}'
# → { "notificationId": "ntf_...", "status": "queued" }# Push (to a user id — fans out to that user's registered devices)
curl -X POST https://myapp.notify.aldero.io/v1/notifications/send \
-H "Authorization: Bearer ${NTF_SECRET_KEY}" \
-H "Content-Type: application/json" \
-d '{
"templateName": "order-confirmation",
"channel": "push",
"to": "usr_abc123",
"variables": { "orderNumber": "12345", "total": "$29.99" }
}'Email attachments are supported (inline base64 or a pre-signed S3 reference via POST /v1/attachments/presign).
Public-beta rate limit: 10 sends per 5 minutes per tenant + environment. Exceeding the cap returns
429. The limit is checked after validation, so malformed requests never burn quota.
Templates
Templates are shared across environments and looked up by name at send time. Use {{variable}} placeholders in the subject and body. Names are unique per tenant.
# Create
curl -X POST https://myapp.notify.aldero.io/v1/templates \
-H "Authorization: Bearer ${NTF_SECRET_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "welcome-email",
"channel": "email",
"subject": "Welcome, {{name}}!",
"body": "Hi {{name}}, thanks for joining."
}'
# → 201 { "templateId": "tpl_...", "name": "welcome-email", ... }# List
curl https://myapp.notify.aldero.io/v1/templates \
-H "Authorization: Bearer ${NTF_SECRET_KEY}"
# → { "templates": [ ... ] }
# Update (PATCH any subset of name/channel/subject/body)
curl -X PATCH https://myapp.notify.aldero.io/v1/templates/tpl_abc \
-H "Authorization: Bearer ${NTF_SECRET_KEY}" \
-H "Content-Type: application/json" \
-d '{ "body": "Hi {{name}}, welcome aboard." }'Creating a duplicate name returns 409. Delete with DELETE /v1/templates/{templateId}.
Devices (push)
Push delivery requires registered device tokens. Register from the client using a publishable key — userId can be a real id or a synthetic one like anon:<uuid>.
curl -X POST https://myapp.notify.aldero.io/v1/devices \
-H "Authorization: Bearer ${NTF_PUBLISHABLE_KEY}" \
-H "Content-Type: application/json" \
-d '{
"userId": "usr_abc123",
"token": "<fcm-or-apns-device-token>",
"platform": "android"
}'
# → 201 { "userId": "usr_abc123", "token": "...", "platform": "android" }Unregister with DELETE /v1/devices/{token}. Send a test push to a single device with POST /v1/devices/{token}/test — invalid tokens are pruned automatically.
Push platform setup
Configure your push provider credentials per environment (server-side, secret key).
# Firebase Cloud Messaging (Android / cross-platform)
curl -X PUT https://myapp.notify.aldero.io/v1/platforms/fcm \
-H "Authorization: Bearer ${NTF_SECRET_KEY}" \
-H "Content-Type: application/json" \
-d '{ "serviceAccountKey": { "type": "service_account", "project_id": "...", "private_key": "...", "client_email": "..." } }'# Apple Push Notification service (iOS)
curl -X PUT https://myapp.notify.aldero.io/v1/platforms/apns \
-H "Authorization: Bearer ${NTF_SECRET_KEY}" \
-H "Content-Type: application/json" \
-d '{
"keyId": "ABC1234567",
"teamId": "DEF1234567",
"privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
"bundleId": "com.example.app",
"environment": "production"
}'List configured platforms with GET /v1/platforms.
Broadcast
POST /v1/notifications/broadcast fans a push template out to every registered device in the tenant. The push channel must be enabled and the template must be a push template.
Pass a dedupeKey for idempotency: a repeated key within 24h is a no-op and returns the original broadcast with status: duplicate.
curl -X POST https://myapp.notify.aldero.io/v1/notifications/broadcast \
-H "Authorization: Bearer ${NTF_SECRET_KEY}" \
-H "Content-Type: application/json" \
-d '{
"templateName": "feature-launch",
"channel": "push",
"dedupeKey": "launch-2026-06",
"variables": { "feature": "Dark Mode" }
}'
# → 202 { "broadcastId": "bct_...", "status": "queued" } (or "duplicate")Rate limit: 10 broadcasts per minute per tenant + environment →
429.
Poll progress with GET /v1/notifications/broadcasts/{id} — it reports enqueuedDevices, sentCount, failedCount, invalidTokenCount, and a status of queued, fanning_out, or fanned_out.
Delivery tracking
Fetch the status of any notification:
curl https://myapp.notify.aldero.io/v1/notifications/ntf_abc \
-H "Authorization: Bearer ${NTF_SECRET_KEY}"
# → { "notificationId": "ntf_abc", "status": "delivered", "channel": "push", "deliveredAt": "...", ... }status moves through queued → sent → delivered → opened (or failed). List and filter with GET /v1/notifications?status=delivered&channel=push (cursor-paginated via nextCursor).
Clients report back delivery and opens:
# Batch-acknowledge delivery (up to 100 at a time)
curl -X POST https://myapp.notify.aldero.io/v1/notifications/ack \
-H "Authorization: Bearer ${NTF_SECRET_KEY}" \
-H "Content-Type: application/json" \
-d '{ "notifications": [
{ "id": "ntf_abc", "context": "background", "timestamp": "2026-06-17T12:00:00Z" }
] }'
# Mark a single notification opened (also marks delivered if it wasn't yet)
curl -X POST https://myapp.notify.aldero.io/v1/notifications/ntf_abc/opened \
-H "Authorization: Bearer ${NTF_SECRET_KEY}"Email domains
By default emails send from the shared Aldero sender. To send from your own domain, start SES verification and add the returned DNS records:
curl -X POST https://myapp.notify.aldero.io/v1/domains/verify \
-H "Authorization: Bearer ${NTF_SECRET_KEY}" \
-H "Content-Type: application/json" \
-d '{ "domain": "mail.example.com", "fromEmail": "hello@mail.example.com", "fromName": "Example" }'
# → { "domain": "mail.example.com", "status": "pending", "dnsRecords": [ ... ] }After adding the records, poll GET /v1/domains/status — it re-checks SES and flips to verified once DNS propagates. Remove a custom domain with DELETE /v1/domains.
Next steps
- Browse every endpoint, field, and error in the API reference.