Notification Service API
Centralized notification delivery service for email, SMS, HubSpot, and Slack channels.
Overview
The Notification Service is a centralized API for all patient and internal notifications.
Instead of each service integrating directly with SES, Twilio, HubSpot, and Slack,
callers send a single POST /notify/send request and let the service handle
template resolution, channel routing, delivery, and logging.
Base URL
https://api.yourera.com/notify
How It Works
- Caller sends a
POST /notify/sendwith a notification type and recipient data - Service resolves the template for that notification type
- Template engine renders the template with provided variables
- Channel config determines which channels are enabled for this type
- Service dispatches to all enabled channels (email, SMS, HubSpot, Slack)
- Each channel delivery is independent — one failure doesn't block others
- All delivery attempts are logged with status, channel, and timestamps
Authentication
The /notify/send endpoint requires HMAC-SHA256 authentication.
Admin endpoints (/notify/templates/*, /notify/channels/*)
require an Admin JWT token.
HMAC Authentication (Send Endpoint)
| Header | Description |
|---|---|
X-API-Key |
Your public API key identifier |
X-Timestamp |
Current timestamp in ISO 8601 format. Must be within 5 minutes of server time. |
X-Signature |
HMAC-SHA256 hex digest of timestamp + '.' + jsonBody |
Signature Formula
HMAC-SHA256(apiSecret, timestamp + '.' + JSON.stringify(body))
Node.js Example
import crypto from 'node:crypto';
const timestamp = new Date().toISOString();
const body = JSON.stringify({
type: 'prescription_approved',
recipient: { email: 'patient@example.com', phone: '5551234567' },
variables: { patientName: 'Jane Doe', medication: 'Semaglutide' }
});
const signature = crypto
.createHmac('sha256', API_SECRET)
.update(timestamp + '.' + body)
.digest('hex');
await fetch('https://api.yourera.com/notify/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY,
'X-Timestamp': timestamp,
'X-Signature': signature,
},
body: body,
});
Send Notification
Send a notification to a patient or internal recipient. The service resolves the appropriate template, renders it with the provided variables, and dispatches to all enabled channels.
Request Body
| Field | Type | Description | |
|---|---|---|---|
type |
string |
required | Notification type. See notification types. |
recipient |
object |
required | Recipient info: { email?: string, phone?: string, name?: string }. At least one of email or phone is required. |
variables |
object |
required | Template variables. Keys match {{variableName}} placeholders in the template. |
channels |
string[] |
optional | Override which channels to use. If omitted, uses the channel config for this type. |
Example Request
{
"type": "prescription_approved",
"recipient": {
"email": "jane@example.com",
"phone": "5041234567",
"name": "Jane Doe"
},
"variables": {
"patientName": "Jane Doe",
"medication": "Semaglutide 5mg/mL",
"pharmacyName": "Galleria Medical Pharmacy"
}
}
Success Response 200
{
"success": true,
"channels": [
{ "channel": "email", "status": "sent" },
{ "channel": "sms", "status": "sent" }
],
"logId": "550e8400-e29b-41d4-a716-446655440000"
}
Error Responses
| Code | Condition | Body |
|---|---|---|
400 |
Unknown notification type | { "error": "Unknown notification type: foo" } |
400 |
Missing required fields | { "error": "Validation failed", "details": [...] } |
400 |
No recipient (email and phone both missing) | { "error": "At least one of email or phone is required" } |
401 |
HMAC auth failure | { "error": "Missing authentication headers" } |
Notification Types
43 notification types organized in 3 categories. Each type is seeded on first deployment with an email template. SMS templates are added as A2P 10DLC registration completes.
General (29 types)
| Type | Description | Required Variables |
|---|---|---|
welcome |
New patient welcome | patientName |
otp |
One-time password for verification | code |
password_reset |
Password reset link | patientName, resetLink |
information_changed |
Profile info was updated | patientName, changedFields |
prescription_changed |
Prescription modification | patientName, medication, change |
what_to_expect |
Post-intake expectations | patientName, intakeType |
doctor_message |
Message from care team | patientName, providerName |
support_message |
Support team message | patientName, message |
first_prescription |
First-ever prescription approved | patientName, medication, providerName, providerSuffix, dosingLine |
new_prescription |
New prescription approved | patientName, medication, pharmacyName |
new_refill |
Refill prescription submitted | patientName, medication |
four_month_checkin |
4-month check-in reminder | patientName |
subscription_renewal |
Subscription auto-renewal notice | patientName, plan, amount, renewalDate |
payment_method_updated |
Card/payment method changed | patientName |
doctor_reviewed |
Doctor completed chart review | patientName, providerName |
magic_link |
Resume intake magic link | magicLinkUrl, intakeType |
follow_up_due |
Follow-up appointment due | patientName, dueDate |
follow_up_past_due |
Follow-up is overdue | patientName, dueDate |
follow_up_two_days |
Follow-up in 2 days | patientName, appointmentDate |
checkin_renewal |
Check-in for subscription renewal | patientName |
visit_scheduled |
Appointment confirmed | patientName, appointmentDate, providerName |
visit_upcoming |
Appointment reminder | patientName, appointmentDate, providerName |
visit_complete |
Visit summary | patientName, providerName |
three_month_checkin |
3-month check-in reminder | patientName |
billing_plan_change |
Plan upgrade/downgrade | patientName, oldPlan, newPlan, amount |
pending_payment |
Payment is due | patientName, amount, dueDate |
treatment_change |
Treatment plan modified | patientName, medication, change |
balance_expiring |
Account balance expiring soon | patientName, balance, expiryDate |
questionnaire_link |
Health questionnaire to complete | patientName, questionnaireUrl |
Orders (12 types)
| Type | Description | Required Variables |
|---|---|---|
first_order_confirmation |
First-ever order placed | patientName, medication, orderNumber |
order_confirmation |
Order placed | patientName, medication, orderNumber |
receipt |
Payment receipt | patientName, amount, orderNumber |
order_edited |
Order was modified | patientName, orderNumber, change |
order_canceled |
Order canceled | patientName, orderNumber, reason |
abandoned_checkout |
Intake started but not finished (30 min) | magicLinkUrl, intakeType |
abandoned_post_checkout |
Payment saved but intake not submitted | patientName, magicLinkUrl |
payment_error |
Payment charge failed | patientName, amount, reason |
lab_received |
Lab sample received | patientName |
lab_resulted |
Lab results ready | patientName |
lab_rejected |
Lab sample rejected | patientName, reason |
treatment_active |
Treatment is now active | patientName, medication |
Shipping (6 types)
| Type | Description | Required Variables |
|---|---|---|
first_shipping_confirmation |
First-ever shipment created | patientName, medication, trackingNumber, carrier |
shipping_confirmation |
Shipment created | patientName, medication, trackingNumber, carrier |
shipping_update |
Shipment status change | patientName, medication, status, trackingNumber, carrier |
delivery_tomorrow |
Package arriving tomorrow | patientName, medication, trackingNumber |
out_for_delivery |
Package out for delivery | patientName, medication, trackingNumber |
delivered |
Package delivered | patientName, medication, trackingNumber |
Channel Matrix
The full channel matrix for all 43 notification types is managed through the Admin Portal.
On initial deployment, all types are seeded with Email enabled and all other
channels disabled. Channels can be toggled per-type via the admin UI or the
PUT /notify/channels/:type API.
Available Channels
| Channel | Provider | Status |
|---|---|---|
| AWS SES | Live | |
| SMS | Twilio | Pending (A2P 10DLC registration) |
| Push | Not implemented | Planned |
| Slack | Slack Webhooks | Internal only |
Template Engine
Templates use Mustache-style {{variableName}} placeholders. The template engine
substitutes variables and handles edge cases gracefully:
- Missing variables render as empty string (no crash)
undefined/nullvariables render as empty string- Variables in email templates are HTML-escaped (XSS prevention)
- Variables in SMS templates are rendered raw (plain text)
- Empty template body causes that channel to be skipped
Example
// Template
"Hi {{patientName}}, your {{medication}} has been approved!"
// Variables
{ "patientName": "Jane", "medication": "Semaglutide" }
// Result
"Hi Jane, your Semaglutide has been approved!"
Templates CRUD
Admin endpoints for managing notification templates. Requires Admin JWT in Authorization: Bearer <token>.
List all notification templates.
Get template for a specific notification type.
Update template for a notification type.
Update Request Body
| Field | Type | Description | |
|---|---|---|---|
emailSubject |
string |
optional | Email subject line template |
emailHtml |
string |
optional | Email HTML body template |
emailText |
string |
optional | Email plain text body template |
smsBody |
string |
optional | SMS message body template |
Channels CRUD
Admin endpoints for managing channel configuration per notification type.
List channel configuration for all notification types.
Update channel configuration for a notification type.
Update Request Body
{
"email": true,
"sms": true,
"hubspot": false,
"slack": false
}
false is allowed. This effectively
disables notifications for that type. The send endpoint will return success with
"channels": [].
Delivery Log
Every notification dispatch is logged with:
| Field | Description |
|---|---|
id | UUID log entry ID |
notificationType | The notification type sent |
recipientEmail | Email address (if sent) |
recipientPhone | Phone number (if sent) |
channels | Array of channel results |
status | "sent", "partial", or "failed" |
createdAt | ISO 8601 timestamp |
Health Check
Health check endpoint. No authentication required.
{
"status": "ok",
"service": "notification-service",
"timestamp": "2026-03-20T12:00:00.000Z"
}
Admin Portal Integration
The admin portal at admin.yourera.com will include a Notifications page
for managing the full notification lifecycle. The page provides:
- Type listing — all 43 types grouped by category (General, Orders, Shipping)
- Channel toggles — enable/disable email, SMS, push per type
- Template editor — edit email subject, HTML body, text body, SMS body for each type
- Delivery log viewer — search/filter notification delivery history
- Test send — send a test notification to verify templates
The admin portal calls the notification service Admin JWT-authenticated endpoints:
| Endpoint | Description |
|---|---|
GET /notify/templates |
Load all templates |
PUT /notify/templates/:type |
Update a template |
GET /notify/channels |
Load channel config |
PUT /notify/channels/:type |
Toggle channels |
GET /notify/log |
Delivery history |
Roadmap
Phase 1 — Email Only (Current)
- 43 notification types seeded with email templates
- Email delivery via AWS SES (
noreply@yourera.com) - Admin portal can toggle types on/off and edit templates
- SMS channel disabled (pending Twilio A2P 10DLC registration)
Phase 2 — SMS
- Complete Twilio A2P 10DLC registration
- Enable SMS templates for patient-facing notifications
- Admin portal gains SMS template editing
Phase 3 — Intake Magic Link + Abandoned Checkout
magic_linkandabandoned_checkouttypes go live- Intake gateway tracks session start timestamps
- 30-minute inactivity trigger sends abandoned_checkout email
- Magic link includes signed token for intake resume
Phase 4 — Scheduled Notifications
- Follow-up reminders (due, past due, 2 days)
- Check-in reminders (3-month, 4-month)
- Subscription renewal notices
- Delivery estimates (tomorrow, out for delivery)
- Requires a notification scheduler (cron or EventBridge)
Phase 5 — Push Notifications
- Mobile push via APNs/FCM
- In-app notification center
- Admin portal gains push template editing
What's Missing (Dependency Tracker)
| Dependency | Blocks | Status |
|---|---|---|
| AWS SES production access (us-east-1) | All email delivery | Pending |
| Twilio A2P 10DLC | SMS delivery | Pending registration |
| Notification service DB created | Service startup | Pending |
| Admin portal notifications page | Template/channel management | Not started |
| Intake gateway magic link flow | abandoned_checkout, magic_link |
Not started |
| EventBridge scheduler | follow_up_*, checkin_*, delivery_* |
Not started |
| Mobile app push integration | Push notifications | Not started |