Skip to content

Notifications

OpenInsure delivers notifications across five channels from a single dispatch endpoint. All channels are optional — the system gracefully skips any channel whose credentials are absent.

Email

Microsoft Graph (O365) or Resend or SMTP

SMS

Twilio

Teams

Microsoft Teams Bot Framework

Slack

Incoming Webhook

In-App

Stored in PlanetScale, served via API


POST /v1/notifications/dispatch
├─ email → createEmailProvider() → Graph / Resend / SMTP
├─ sms → createTwilioClient() → Twilio REST API
├─ teams → createTeamsBotClient() → Bot Framework / Graph
├─ slack → createSlackClient() → Incoming Webhook
└─ in_app → db.insert(notifications)
communicationsLedger (delivery audit trail)

The dispatchNotification() function in packages/notify/src/index.ts fans out to all requested channels in parallel and returns a per-channel result. Results are written to communications_ledger for audit.


Set EMAIL_PROVIDER in .dev.vars or wrangler.toml [vars]:

ValueProviderBest for
graphMicrosoft Graph sendMailO365 licensed mailboxes, MGA tenants
resendResend APITransactional email to external recipients
smtpSMTP relaySelf-hosted or custom relay

The Graph provider is the default in production (EMAIL_PROVIDER=graph in wrangler.toml).

Terminal window
wrangler secret put EMAIL_PROVIDER # graph
wrangler secret put AZURE_TENANT_ID
wrangler secret put AZURE_CLIENT_ID
wrangler secret put AZURE_CLIENT_SECRET
wrangler secret put GRAPH_MAIL_FROM # jd@openinsure.dev

See Microsoft 365 Integration for full setup details.

Terminal window
wrangler secret put EMAIL_PROVIDER # resend
wrangler secret put RESEND_API_KEY # re_...
wrangler secret put RESEND_FROM # noreply@openinsure.dev

SMS is delivered via Twilio Programmable SMS. The client is created only when both TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN are present.

Terminal window
wrangler secret put TWILIO_ACCOUNT_SID
wrangler secret put TWILIO_AUTH_TOKEN
wrangler secret put TWILIO_FROM_NUMBER # +18005551234

Teams messages are dispatched via the Bot Framework. The Notifications Bot app registration is configured in wrangler.toml:

[vars]
TEAMS_BOT_APP_ID = "ac81bbbd-53fe-4b8a-8755-dafded231e19"
TEAMS_BOT_TENANT_ID = "ebd58a52-c818-4230-b150-348ae1e17975"
Terminal window
wrangler secret put TEAMS_BOT_APP_PASSWORD

Slack notifications use an incoming webhook URL. No OAuth is required.

Terminal window
wrangler secret put SLACK_WEBHOOK_URL # https://hooks.slack.com/services/...

In-app notifications are stored in PlanetScale (notifications table) and surfaced via the API. The client polls or subscribes via SSE.

Endpoints:

MethodPathDescription
GET/v1/notifications?orgId=&read=falseList notifications
POST/v1/notifications/:id/readMark single read
POST/v1/notifications/read-allMark all read

Terminal window
POST /v1/notifications/dispatch
Authorization: Bearer {token}
Content-Type: application/json
{
"orgId": "00000000-0000-4000-a000-000000000001",
"userId": "10000000-0000-4000-a000-000000000010",
"type": "submission_referred",
"title": "New Submission Referred",
"body": "A new GL submission from Acme Hardware has been referred for UW review.",
"entityType": "submission",
"entityId": "...",
"template": "submission_referred",
"templateData": {
"submissionId": "SUB-2026-00042",
"insuredName": "Acme Hardware",
"line": "General Liability"
},
"channels": ["email", "teams", "in_app"],
"email": { "to": "underwriter@mhcmga.com" },
"teams": { "to": "underwriting@mhcmga.com" }
}
TemplateTriggered by
policy_boundPolicy binds
claim_openedFNOL submitted
claim_settledClaim closed
quote_availableUW approves quote
renewal_reminder60/30/15 days before expiry
invoice_generatedBilling cycle runs
compliance_deadlineFiling due date approaching
approval_neededAuthority limit exceeded
bordereaux_submittedBordereaux sent to carrier
noc_deliveryNotice of cancellation issued
submission_referredSubmission escalated for review
endorsement_issuedMid-term endorsement processed
cancellation_completedPolicy cancelled
reinstatement_completedPolicy reinstated
audit_completedPremium audit finalized
nonrenewal_noticeNon-renewal notice issued
subrogation_updateSubrogation status change
{
"ok": true,
"result": {
"email": { "success": true, "providerMessageId": "msg_..." },
"teams": { "success": false, "error": "ChatMessage.Send permission not granted" },
"inApp": { "success": true }
}
}

Every email and SMS dispatch is written to the communications_ledger table for compliance audit:

Terminal window
GET /v1/notifications/ledger?orgId=&status=failed&entityType=policy

The ledger captures: channel, provider, recipient, subject, status (sent / failed), provider message ID, and trace ID.


  1. Add the template key to the template enum in apps/api/src/routes/notifications.ts 2. Add the template rendering logic in packages/notify/src/templates/ 3. Document the trigger condition in the table above 4. Add tests in packages/notify/src/__tests__/