Appearance
SMS Sending Workflow
The Notifications module can send SMS messages through Twilio. The current implementation keeps SMS delivery simple: it sends a raw message body, records the delivery attempt, and exposes a development-only endpoint for manual testing.
How It Works
- A caller sends a request to
POST /api/notifications/sms/test. - The
SmsControllervalidates the payload with the sharedsendTestSmsSchema. - The controller dispatches a
SendSmsNotificationCommandwith the fixed log keymanual-test-sms. - The
SendSmsNotificationHandlercalls theTwilioSmsAdapter, emits structured app logs for provider failures, and persists aNotificationLogwithtype: SMS. - On success, the API returns the Twilio message SID as
providerMessageId. - On failure, the command still writes a failed notification log and returns an application error.
Required Twilio Environment Variables
TWILIO_ACCOUNT_SID: Twilio account SID used to authenticate the SDK.TWILIO_AUTH_TOKEN: Twilio auth token paired with the account SID.TWILIO_MESSAGING_SERVICE_SID: Recommended sender configuration when using a Twilio Messaging Service.TWILIO_FROM_PHONE_NUMBER: Fallback sender number in E.164 format when a messaging service is not used.
At least one sender option must be configured: TWILIO_MESSAGING_SERVICE_SID or TWILIO_FROM_PHONE_NUMBER.
Test Endpoint
- Route:
POST /api/notifications/sms/test - Availability: development only
- Rate limit: 3 requests per 5 minutes per IP
- Request body:
to: destination phone number in E.164 formatmessage: SMS body text
Example payload:
json
{
"to": "+15555550123",
"message": "Hello from DaraMex"
}Twilio Notes
- Twilio expects phone numbers in E.164 format.
- Trial Twilio accounts can only send to verified recipient numbers.
- If both sender options are configured, the adapter prefers
TWILIO_MESSAGING_SERVICE_SIDoverTWILIO_FROM_PHONE_NUMBER.
Observability
SMS failures now emit structured OTEL log events through AppLoggerService in addition to the notifications.notification_logs audit row:
notifications.sms.provider_misconfigured: emitted when Twilio credentials or sender configuration are missing.notifications.sms.delivery_failed: emitted when Twilio rejects or fails a send attempt.notifications.sms.log_persist_failed: emitted when theNotificationLogrow cannot be saved.
These events include templateKey, recipient, channel, any available entity IDs, and Twilio-specific diagnostics when present (providerErrorCode, providerMoreInfo, providerDetails, or missingVariables). This makes provider failures queryable in Loki without inspecting the database directly.
Error Handling
If Twilio is not configured or rejects the request, the API returns an application error, emits a structured app log, and stores the failure reason in notifications.notification_logs.error. For Twilio RestException responses, the stored value is a JSON string that includes message, code, moreInfo, and details, so provider diagnostics are preserved for debugging in both the database row and the OTEL log stream.