Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Version: 1.0.0
Created: 2026-01-24
Status: ✅ Implemented
Spec Reference: specs/ce/specs/CE-08-sms-messaging-integration.md

Overview

This document defines the integration contracts for CE-08 (SMS/Text Messaging Integration). CE-08 integrates with multiple internal modules (CE-01, CE-03, CE-04, PF-10) and external services (Twilio SMS API).

Integration Patterns

Pattern Summary

IntegrationPatternDirectionStatus
CE-01 (Contacts)Direct ReferenceCE-08 → CE-01✅ Implemented
CE-03 (Telephony)Platform Integration LayerCE-08 → CE-03✅ Implemented
CE-04 (Activities)Database TriggerCE-08 → CE-04✅ Implemented
PF-10 (Notifications)Platform Integration LayerCE-08 → PF-10✅ Implemented
Twilio SMS APIExternal APICE-08 ↔ Twilio✅ Implemented

Internal Integrations

CE-01: Contacts Integration

Pattern: Direct Reference (Foreign Key)
Direction: CE-08 → CE-01
-- SMS messages linked to contacts via foreign key
ce_sms_messages.contact_idce_contacts.id

-- Consent tracked per contact phone
ce_sms_consent.contact_idce_contacts.id
Integration Points:
  • SMS matched to contact by phone number (E.164 format)
  • Contact detail includes SMS conversation tab
  • Consent status displayed on contact
  • SMS compose from contact detail page
API Contract:
// Phone-to-contact lookup
const contact = await supabase
  .from('ce_contacts')
  .select('id, first_name, last_name, phone, mobile_phone')
  .eq('organization_id', orgId)
  .or(`phone.eq.${normalizedPhone},mobile_phone.eq.${normalizedPhone}`)
  .single();

CE-03: Platform Telephony Integration

Pattern: Platform Integration Layer
Direction: CE-08 → CE-03
Usage: Extend Platform Telephony Layer to include SMS alongside calls Import:
import { useTelephonyHistory } from '@/platform/telephony';
Integration Points:
  • Unified communication history (calls + SMS)
  • Shared phone number formatting utilities
  • RingCentral SMS API (if using RingCentral for telephony)

CE-04: Activities Integration

Pattern: Database Trigger (Event-Based)
Direction: CE-08 → CE-04
Trigger Contract:
-- Trigger: Auto-create activity when SMS sent/received
CREATE TRIGGER ce_sms_create_activity
  BEFORE INSERT ON ce_sms_messages
  FOR EACH ROW
  EXECUTE FUNCTION ce_create_activity_from_sms();
Activity Created:
interface SmsActivity {
  organization_id: string;
  contact_id: string | null;
  partner_id: string | null;
  lead_id: string | null;
  activity_type: 'sms';
  subject: string; // "SMS to [contact]" or "SMS from [contact]"
  description: string; // Message preview (first 100 chars)
  status: 'completed';
  activity_date: string; // ISO timestamp
  created_by: string | null;
}

PF-10: Notifications Integration

Pattern: Platform Integration Layer
Direction: CE-08 → PF-10
Usage: In-app notifications for inbound SMS Import:
import { sendNotification } from '@/platform/notifications';
Notification Types:
EventNotification TypeRecipients
Inbound SMSsms_receivedUser assigned to contact
Delivery failuresms_failedSender
Opt-out receivedsms_opted_outAll org users with contact
Notification Payload:
interface SmsNotification {
  type: 'sms_received' | 'sms_failed' | 'sms_opted_out';
  recipient_user_id: string;
  data: {
    sms_message_id: string;
    contact_name: string;
    phone_number_masked: string; // Last 4 digits only
    preview: string; // First 50 chars
    event_timestamp: string;
    error_code?: string; // For failures
  };
}

External Integrations

Twilio SMS API Integration

Pattern: External API
Direction: Bi-directional
API Configuration:
const TWILIO_CONFIG = {
  accountSid: process.env.TWILIO_ACCOUNT_SID,
  authToken: process.env.TWILIO_AUTH_TOKEN,
  // Webhooks
  inboundWebhookUrl: '/functions/v1/sms-webhook',
  statusCallbackUrl: '/functions/v1/sms-webhook/status',
};
API Endpoints Used:
OperationEndpointMethod
Send SMS/2010-04-01/Accounts/{SID}/Messages.jsonPOST
Get message/2010-04-01/Accounts/{SID}/Messages/{SID}.jsonGET
List messages/2010-04-01/Accounts/{SID}/Messages.jsonGET
Buy number/2010-04-01/Accounts/{SID}/IncomingPhoneNumbers.jsonPOST
Edge Functions:
  • sms-send/index.ts - Send SMS via Twilio
  • sms-webhook/index.ts - Receive inbound SMS and status updates
Request/Response Schemas: Send SMS Request:
interface SendSmsRequest {
  organization_id: string;
  to_number: string; // E.164 format
  body: string;
  contact_id?: string;
  template_id?: string;
}

interface SendSmsResponse {
  success: boolean;
  message_id?: string;
  external_message_id?: string; // Twilio SID
  segment_count?: number;
  error?: string;
}
Webhook Payload (Inbound):
interface TwilioInboundWebhook {
  MessageSid: string;
  From: string; // E.164
  To: string; // E.164
  Body: string;
  NumSegments: string;
  AccountSid: string;
}
Webhook Payload (Status):
interface TwilioStatusWebhook {
  MessageSid: string;
  MessageStatus: 'queued' | 'sent' | 'delivered' | 'failed' | 'undelivered';
  ErrorCode?: string;
  ErrorMessage?: string;
}

Event Contracts

SMS Sent Event

Event Name: ce.sms.sent
Publisher: CE-08
Subscribers: CE-04 (Activity creation)
Payload Schema:
interface SmsSentEvent {
  event_type: 'ce.sms.sent';
  organization_id: string;
  sms_message_id: string;
  contact_id: string | null;
  to_number_masked: string; // Last 4 digits
  segment_count: number;
  user_id: string; // Sender
  timestamp: string;
}

SMS Received Event

Event Name: ce.sms.received
Publisher: CE-08 (webhook Edge Function)
Subscribers: PF-10 (Notifications), CE-04 (Activity creation)
Payload Schema:
interface SmsReceivedEvent {
  event_type: 'ce.sms.received';
  organization_id: string;
  sms_message_id: string;
  contact_id: string | null;
  from_number_masked: string; // Last 4 digits
  preview: string; // First 50 chars
  timestamp: string;
}
Event Name: ce.sms.consent_changed
Publisher: CE-08
Subscribers: Audit logging
Payload Schema:
interface ConsentChangedEvent {
  event_type: 'ce.sms.consent_changed';
  organization_id: string;
  consent_id: string;
  contact_id: string | null;
  phone_number_masked: string; // Last 4 digits
  old_status: string;
  new_status: string;
  method: string; // How consent was changed
  timestamp: string;
}

TCPA Compliance Contract

Express Written Consent (Marketing):
  • Required before sending marketing messages
  • Must capture: timestamp, method, source
  • Must be stored in ce_sms_consent table
Prior Express Consent (Informational):
  • Required for informational messages
  • Can be implied from business relationship
  • Document consent source

Opt-Out Contract

Keywords Recognized:
  • STOP, UNSUBSCRIBE, CANCEL, END, QUIT (case-insensitive)
Processing Requirements:
  1. Detect keyword in inbound message
  2. Update ce_sms_consent.consent_status to opted_out
  3. Record opted_out_at timestamp and opted_out_keyword
  4. Send confirmation: “You have been unsubscribed. Reply START to resubscribe.”
  5. Log activity for compliance audit
  6. Notify assigned users
Enforcement:
  • Hard block on sending to opted-out numbers
  • Check performed in sms-send Edge Function before API call
  • RLS does NOT prevent viewing opted-out contacts (for compliance review)

Security Considerations

Phone Number Privacy

  • Phone numbers stored in E.164 format
  • Display masked in UI (show last 4 digits only)
  • No phone numbers in application logs
  • Encrypted in transit (TLS 1.2+)

Twilio Credential Security

  • Credentials stored in Supabase Secrets
  • Never exposed in client-side code
  • Webhook signature validation required

PHI Detection

  • Message content scanned for PHI patterns
  • Warning shown to user before send (not hard block)
  • Patterns: SSN, DOB formats, medical terms
  • Configurable via sms_phi_detection_mode setting

Module Settings

Settings stored in ce_module_settings:
SettingTypeDefaultDescription
sms_retention_daysINTEGER730Days to retain SMS messages (90-2555)
sms_opt_out_footerTEXT’Reply STOP to opt-out’Footer for marketing messages
sms_phi_detection_enabledBOOLEANtrueEnable PHI pattern detection
sms_phi_detection_modeTEXT’warn’PHI detection behavior: warn, block, disabled
twilio_phone_numberTEXTnullOrganization Twilio number (E.164)
sms_business_hours_startTIME’09:00:00’Start of SMS business hours
sms_business_hours_endTIME’18:00:00’End of SMS business hours

Implementation Status

ComponentStatusNotes
Database schema📋 Planned3 tables defined in spec
Twilio setup📋 PlannedCredentials and webhooks
Send Edge Function📋 PlannedPhase 2
Webhook Edge Function📋 PlannedPhase 2
Consent management📋 PlannedPhase 3
Conversation UI📋 PlannedPhase 3
Templates📋 PlannedPhase 4

Security & Compliance Controls

CE-08 implements comprehensive security and compliance controls for SMS messaging:

PHI Detection

Implementation: supabase/functions/sms-send/index.ts
  • PHI detection runs before message send (when phiDetectionEnabled is true in provider config)
  • Detected PHI patterns are logged to ce_sms_messages.phi_detected and phi_detection_result fields
  • Detection uses pattern matching from _shared/phi-detection.ts utility
  • PHI detection results are included in audit logs for compliance review

TCPA Opt-Out Handling

Implementation: supabase/functions/sms-webhook/index.ts
  • Opt-out keywords detected: STOP, UNSUBSCRIBE, CANCEL, END, QUIT, STOPALL, UNSUBSCRIBEALL
  • Automatic consent revocation when opt-out keywords are received
  • Confirmation message sent: “You have been unsubscribed and will no longer receive SMS messages from us.”
  • Consent status updated in ce_sms_consent table with consent_status = 'revoked' and revoked_at timestamp
  • Future sends blocked via checkSmsConsent() validation in sms-send function

Webhook Signature Validation

Implementation: supabase/functions/sms-webhook/index.ts, supabase/functions/_shared/twilio-validate.ts
  • Twilio webhooks validated using X-Twilio-Signature header and HMAC-SHA1 signature verification
  • Signature validation ensures webhook authenticity and prevents spoofing
  • RingCentral webhooks validated via Validation-Token header for subscription validation
  • Invalid signatures result in 403 Forbidden responses

Provider Abstraction & Configuration

Implementation: supabase/functions/_shared/sms-provider.ts, supabase/functions/_shared/twilio-config.ts
  • Unified provider abstraction supports Twilio and RingCentral
  • Provider configuration loaded from ce_module_settings with fallback to environment variables
  • Business hours enforcement via isWithinBusinessHours() utility
  • Phone number normalization to E.164 format via normalizeToE164()
  • Segment calculation for multi-part messages via calculateSmsSegments()
Implementation: supabase/functions/_shared/sms-provider.ts
  • checkSmsConsent() validates consent status before sending
  • Consent checked per contact phone number in ce_sms_consent table
  • Required consent status: 'granted' with valid granted_at timestamp
  • Revoked consent blocks all future sends until new consent is granted

References


Last Updated: 2026-01-24