Files
coordination-engine/spec/SmsAdapterSpecification.md

64 KiB
Raw Blame History

I used current provider documentation and industry guidance to ground the SMS model. Twilios outbound status model includes states such as queued/sending/sent/delivered/undelivered/failed, and notes that sent may remain without final delivery status in some cases. (help.twilio.com) Vonages SMS DLRs include accepted, delivered, buffered, expired, failed, rejected, and unknown; Vonage also notes DLRs are returned when received from downstream carriers. (developer.vonage.com) Sinchs SMS delivery reports use statuses such as queued, dispatched, delivered and error codes, while Bird/MessageBird distinguish delivered from not delivered and provide reason codes such as unknown subscriber. (developers.sinch.com) SMS content length, encoding, and concatenation matter because GSM-7, UCS-2, and multi-segment messages affect cost, delivery behavior, and diagnostics. (Twilio) For compliance-sensitive SMS, opt-in/opt-out, STOP/HELP handling, and sender registration are first-class channel concerns; Twilio documents Advanced Opt-Out and A2P 10DLC registration, while CTIA guidance emphasizes documenting consent and respecting opt-out. (Twilio)

SmsAdapterSpecification.md

1. Document Status

Document: SmsAdapterSpecification.md Project: sms-connect Target Integration: coordination-engine Adapter Contract: AdapterInterfaceSpecification.md v1.0 Status: Draft v1.0 Primary Scope: SMS protocol and provider integration as a coordination-engine adapter

2. Purpose

This document specifies how sms-connect models SMS as a communication protocol and how it integrates with coordination-engine.

sms-connect is a channel adapter for short-message communication. It provides SMS-specific sending, delivery receipt ingestion, status normalization, phone endpoint quality handling, opt-out/suppression handling, inbound reply processing, evidence classification, and provider abstraction.

SMS is often stronger than email for endpoint-level delivery evidence because carriers and providers may return delivery receipts indicating that a message reached the receiving network or handset. However, SMS still does not normally prove human awareness, comprehension, identity-bound interaction, payload access, or final coordination success.

The key design objective is to make SMS useful as a notification, reminder, escalation, and lightweight interaction channel without overclaiming what SMS can prove.

3. Core Principle

SMS is a medium-strength notification channel with better endpoint-delivery evidence than email in many cases, but it is still not a reliable proof channel for human awareness or result completion.

The adapter MUST distinguish:

provider acceptance
carrier or downstream network acceptance
delivery receipt
temporary delivery uncertainty
permanent delivery failure
recipient reply
opt-out or suppression
link interaction
identity-bound interaction from another system
coordination result evidence

In the coordination model, SMS delivery receipts can support stronger notification evidence than email MX acceptance, but SMS events alone usually remain insufficient for high-assurance scenarios unless the intended result explicitly accepts SMS delivery or SMS reply as sufficient.

4. Architectural Role

4.1 Standalone Role

As a standalone component, sms-connect provides:

  • provider-neutral SMS sending
  • transactional SMS dispatch
  • provider and carrier delivery receipt ingestion
  • message status normalization
  • phone number endpoint diagnostics
  • SMS segmentation and encoding diagnostics
  • inbound SMS reply handling
  • opt-in, opt-out, HELP, START, and STOP keyword handling
  • suppression management
  • sender identity and campaign metadata tracking
  • SMS message timelines
  • delivery failure classification
  • channel health and compliance diagnostics
  • normalized SMS evidence stream

4.2 coordination-engine Adapter Role

As a coordination-engine adapter, sms-connect provides:

Actions

  • notification.send
  • notification.send_reminder
  • notification.schedule
  • notification.cancel where technically possible before dispatch
  • recipient.suppress
  • recipient.unsuppress
  • recipient.opt_in_record
  • recipient.opt_out_record
  • notification.register_tracking_context

Signals

  • notification.attempt.accepted_by_adapter
  • notification.attempt.rejected_by_adapter
  • notification.attempt.accepted_by_provider
  • notification.attempt.rejected_by_provider
  • notification.attempt.queued
  • notification.attempt.scheduled
  • notification.attempt.delayed
  • notification.endpoint.accepted
  • notification.endpoint.deferred
  • notification.endpoint.rejected_temporary
  • notification.endpoint.rejected_permanent
  • notification.endpoint.unreachable
  • notification.endpoint.unknown
  • notification.channel.suppression_added
  • notification.channel.suppression_removed
  • notification.channel.complaint_received
  • notification.channel.unsubscribe_received
  • notification.channel.reputation_warning
  • interaction.reply_received
  • interaction.acknowledgement_recorded
  • interaction.unverified_actor_interaction
  • interaction.authenticated_actor_interaction only when paired with trusted identity evidence
  • system.provider.degraded
  • system.provider.unavailable

5. Relationship to coordination-engine

sms-connect does not own:

  • CoordinationCase
  • intended result evaluation
  • participant-level success
  • case-level success
  • legal notification interpretation
  • portal access
  • payload retrieval
  • payment settlement
  • signature completion
  • multi-channel escalation policy
  • final closure decisions

sms-connect owns:

  • SMS send requests
  • SMS provider abstraction
  • provider and carrier identifiers
  • SMS delivery receipt ingestion
  • SMS status classification
  • SMS-native message timeline
  • phone endpoint diagnostics
  • SMS reply classification
  • opt-out and suppression handling
  • SMS evidence mapping
  • SMS-specific uncertainty classification

The boundary rule is:

sms-connect reports what happened in the SMS channel and what that may indicate. coordination-engine decides what that means for the coordination case.

6. SMS as Notification, Lightweight Payload, and Response Channel

Within coordination-engine, SMS is primarily a notification and reminder channel.

SMS may also carry lightweight inline payloads or action prompts, such as:

  • one-time codes
  • short status alerts
  • short links
  • payment links
  • confirmation prompts
  • reply keywords
  • appointment reminders
  • urgent escalation notices

However, for most coordination scenarios, SMS should point participants toward an action surface such as:

  • portal page
  • mobile app screen
  • payment page
  • signature flow
  • upload form
  • approval screen
  • support flow

The actual payload access or result-relevant action is usually observed by another adapter.

Example:

sms-connect:
  notification.endpoint.accepted
  interaction.reply_received

portal-connect:
  identity.actor_authenticated
  delivery.payload.downloaded

coordination-engine:
  participant result satisfied

SMS delivery to handset or network is stronger than provider acceptance but still does not prove that the intended human read, understood, or acted on the message.

7. SMS Message Lifecycle Model

sms-connect models an SMS notification as a lifecycle with observable phases.

message.created
message.rendered
message.render_failed
message.segmentation_analyzed
message.consent_checked
message.suppression_checked
message.send_requested
message.accepted_by_adapter
message.rejected_by_adapter
message.accepted_by_provider
message.rejected_by_provider
message.queued
message.scheduled
message.dispatched
message.accepted_by_carrier
message.buffered
message.deferred
message.delivered
message.undelivered
message.failed
message.rejected
message.expired
message.unknown
message.inbound_reply_received
message.opt_out_received
message.opt_in_received
message.help_received
message.link_clicked
message.suppression_added
message.channel_warning

The lifecycle is not strictly linear. Events may arrive late, out of order, duplicated, partially aggregated, or missing.

8. SMS Message vs Attempt vs Segment vs Recipient

The adapter MUST distinguish at least four layers.

8.1 SmsMessage

The logical SMS message created by a client or coordination case.

SmsMessage:
  sms_message_id: string
  coordination_case_id: string?
  participant_id: string?
  purpose: string?
  message_body_ref: string?
  template_ref: string?
  tracking_context: TrackingContext
  created_at: timestamp

8.2 SmsAttempt

One send attempt through one provider/configuration.

SmsAttempt:
  sms_attempt_id: string
  sms_message_id: string
  provider_name: string
  provider_account_ref: string?
  sender_endpoint: SmsEndpoint
  recipient_endpoint: SmsEndpoint
  provider_message_id: string?
  adapter_operation_id: string?
  sender_identity_ref: string?
  campaign_ref: string?
  state: SmsAttemptState
  created_at: timestamp
  updated_at: timestamp

8.3 SmsSegment

A logical SMS may be split into multiple billable/deliverable segments.

SmsSegment:
  sms_segment_id: string
  sms_attempt_id: string
  segment_index: integer
  segment_count: integer
  encoding: gsm7 | ucs2 | binary | unknown
  provider_segment_id: string?
  carrier_segment_id: string?
  state: SmsSegmentState
  delivered_at: timestamp?
  failed_at: timestamp?

Segmentation matters for cost, deliverability diagnostics, and partial-failure interpretation. For coordination evidence, a multi-segment message should normally be considered delivered only when the provider or carrier reports the message as delivered or enough segment-level evidence exists according to provider semantics.

8.4 SmsEndpoint

The target or sender endpoint.

SmsEndpoint:
  endpoint_id: string?
  endpoint_type: phone_number | short_code | long_code | toll_free | alphanumeric_sender_id | sender_pool | unknown
  phone_number_e164: string?
  sender_id: string?
  display_name: string?
  country_code: string?
  verification_state: unknown | syntax_validated | verified | suspected_invalid | invalid
  consent_state: unknown | opted_in | opted_out | consent_not_required | consent_required | disputed
  suppression_state: active | suppressed | opt_out_suppressed | bounce_suppressed | provider_suppressed | manual_suppressed | unknown
  metadata: object?

Per-recipient modeling is required. The preferred coordination mode is one logical notification attempt per participant endpoint.

9. SMS Attempt States

The adapter SHOULD support these attempt states:

created
rendered
render_failed
consent_blocked
suppressed
send_requested
accepted_by_adapter
rejected_by_adapter
accepted_by_provider
rejected_by_provider
queued
scheduled
dispatched
accepted_by_carrier
buffered
deferred
delivered
undelivered
failed
rejected
expired
unknown
reply_received
opt_out_received
opt_in_received
help_received
channel_degraded

These states are SMS-native. They are not coordination result states.

10. SMS Evidence Assessment

sms-connect should provide an SMS-native assessment separate from coordination-engine state.

SmsEvidenceAssessment:
  sms_message_id: string
  participant_id: string?
  category: success | fail | undef
  subclass: string
  confidence: low | medium | high
  strongest_signal: string?
  evidence_summary:
    - string
  recommended_coordination_interpretation: string?

The assessment categories are adapter-level hints.

10.1 SMS Adapter Success

SMS-level success means the SMS channel produced strong SMS-channel evidence.

Possible subclasses:

success.provider_accepted
success.carrier_accepted
success.delivered
success.reply_received
success.acknowledgement_reply_received
success.link_clicked

Important: These are not automatically coordination success.

success.delivered usually means a provider or carrier reports delivery to the handset or receiving network. It is stronger than email server acceptance, but it still does not prove human awareness unless scenario policy accepts delivery receipt as sufficient.

10.2 SMS Adapter Fail

SMS-level fail indicates strong evidence that the SMS channel failed or should not be used.

Subclasses:

fail.missing_number
fail.invalid_number_format
fail.not_mobile_number
fail.unknown_subscriber
fail.unreachable_subscriber
fail.unavailable_subscriber
fail.ported_number_issue
fail.blocked_by_recipient
fail.opted_out
fail.consent_missing
fail.suppressed
fail.provider_rejected
fail.carrier_rejected
fail.filtered_by_carrier
fail.policy_rejected
fail.content_rejected
fail.sender_not_registered
fail.sender_not_allowed
fail.route_unavailable
fail.expired
fail.delivery_failed
fail.message_too_long_or_invalid
fail.encoding_unsupported
fail.account_or_quota_failure

10.3 SMS Adapter Undef

SMS-level undef is used when the adapter cannot determine final delivery or human awareness.

Subclasses:

undef.pending
undef.provider_accepted_only
undef.queued
undef.dispatched
undef.carrier_accepted_only
undef.buffered
undef.deferred
undef.no_dlr
undef.dlr_unknown
undef.delivery_status_unknown
undef.delivery_receipt_missing
undef.delivered_but_awareness_unproven
undef.link_clicked_identity_uncertain
undef.reply_identity_uncertain
undef.conflicting_evidence
undef.channel_degraded
undef.expired_unknown

The undef category must not be empty because SMS delivery reporting is provider-, route-, country-, carrier-, and device-dependent.

11. Detailed SMS Scenario Classification

11.1 Pre-Send Scenarios

Scenario SMS assessment Normalized event Notes
Missing number fail.missing_number notification.attempt.rejected_by_adapter No send possible
Invalid phone number syntax fail.invalid_number_format notification.attempt.rejected_by_adapter Strong local failure
Number not suitable for SMS fail.not_mobile_number notification.attempt.rejected_by_adapter Landline or unsupported endpoint
Missing consent where required fail.consent_missing notification.attempt.rejected_by_adapter Policy/compliance block
Recipient opted out fail.opted_out notification.channel.suppression_added Channel blocked
Suppression hit fail.suppressed notification.channel.suppression_added Channel blocked
Template rendering failure fail.message_too_long_or_invalid or fail.provider_rejected notification.attempt.rejected_by_adapter Notification unusable
Message contains invalid link fail.message_too_long_or_invalid or scenario-specific failure notification.attempt.rejected_by_adapter Especially relevant for portal links
Sender/campaign missing fail.sender_not_registered or fail.sender_not_allowed notification.attempt.rejected_by_adapter Common in regulated routes
Provider unavailable before acceptance undef.pending or fail.provider_rejected action error Depends on retryability
Submission timeout undef.pending action result unknown Could have been accepted despite timeout

11.2 Provider-Side Scenarios

Scenario SMS assessment Normalized event Notes
Adapter accepted request undef.pending notification.attempt.accepted_by_adapter Adapter accepted work
Provider accepted message undef.provider_accepted_only notification.attempt.accepted_by_provider Sending began
Provider rejected message fail.provider_rejected notification.attempt.rejected_by_provider Strong attempt failure
Provider queued message undef.queued notification.attempt.queued Pending
Provider scheduled message undef.pending notification.attempt.scheduled Not yet sent
Provider dispatched message undef.dispatched notification.attempt.accepted_by_provider or metadata Provider handed off downstream
Provider delayed message undef.deferred notification.attempt.delayed Pending/degraded
Provider route unavailable fail.route_unavailable notification.attempt.rejected_by_provider Strong channel/route failure
Provider quota/account failure fail.account_or_quota_failure notification.attempt.rejected_by_provider Operational failure
Provider suppression fail.suppressed notification.channel.suppression_added Channel blocked

11.3 Carrier and Downstream Network Scenarios

Scenario SMS assessment Normalized event Notes
Carrier accepted undef.carrier_accepted_only notification.endpoint.accepted Stronger than provider-only, still not handset proof
Buffered undef.buffered notification.endpoint.deferred Held for later delivery
Deferred undef.deferred notification.endpoint.deferred Retry or wait
Delivered success.delivered notification.endpoint.accepted with delivery metadata Strong endpoint evidence, not human awareness
Undelivered fail.delivery_failed notification.endpoint.rejected_permanent or temporary Use reason code
Failed fail.delivery_failed notification.endpoint.rejected_permanent Strong negative evidence if final
Rejected fail.carrier_rejected notification.endpoint.rejected_permanent Carrier refused delivery
Expired fail.expired or undef.expired_unknown notification.endpoint.unknown or rejected temporary/permanent Depends on provider semantics
Unknown undef.dlr_unknown notification.endpoint.unknown No useful final status
No DLR received undef.no_dlr none or timeout event Common on some routes
Delivery receipt late update current assessment corresponding event Must be accepted if relevant
Conflicting delivery reports undef.conflicting_evidence multiple events Preserve all evidence

11.4 Device and Recipient Availability Scenarios

Scenario SMS assessment Notes
Handset off or unreachable undef.deferred or fail.unreachable_subscriber Depending on final DLR
Subscriber unavailable undef.deferred or fail.unavailable_subscriber Carrier-specific
Unknown subscriber fail.unknown_subscriber Remove or verify number
Roaming issue undef.deferred or fail.route_unavailable Route/country dependent
Blocked by recipient fail.blocked_by_recipient If provider/carrier reports it
Carrier filtering fail.filtered_by_carrier Often content/campaign/sender issue
Device received but user ignored undef.delivered_but_awareness_unproven Delivery does not prove reading
SIM swap/number reassigned undef.identity_uncertain if suspected Requires external identity/number intelligence
Shared phone undef.identity_uncertain Intended participant uncertain
Corporate device management undef.delivered_but_awareness_unproven User awareness uncertain

SMS itself does not provide open tracking. Link interaction must be observed through tracked links or action surfaces.

Scenario SMS assessment Normalized event Notes
No link click undef.no_signal none Not evidence of failure
Link clicked success.link_clicked or undef.link_clicked_identity_uncertain interaction.unverified_actor_interaction Identity uncertain
Link clicked then authenticated portal login SMS event remains weak; portal event is strong Portal adapter provides identity evidence
Link clicked then payload downloaded SMS contributed path evidence; delivery evidence is decisive Portal/delivery adapter closes result
Link scanner or preview fetch undef.link_clicked_identity_uncertain or scanner-like if detected interaction.scanner_or_bot_interaction Less common than email but possible
Expired link clicked undef.link_clicked_identity_uncertain interaction plus access failure Awareness possible, action path failed
Forwarded SMS link clicked undef.identity_uncertain unverified interaction Intended actor unknown

11.6 Inbound Reply Scenarios

SMS can be a useful lightweight response channel.

Scenario SMS assessment Normalized event Notes
Any reply received success.reply_received interaction.reply_received Strong awareness signal, identity may still need validation
YES/OK/ACK reply success.acknowledgement_reply_received interaction.acknowledgement_recorded if policy accepts Can be result evidence in low/medium assurance cases
STOP / unsubscribe fail.opted_out notification.channel.unsubscribe_received + suppression Future channel constraint
START / opt-in active/unknown notification.channel.suppression_removed or opt-in metadata Channel may become usable
HELP neutral interaction.reply_received Support/compliance event
Free-text question success.reply_received interaction.reply_received May trigger support workflow
Reply from reassigned/shared number undef.reply_identity_uncertain interaction.reply_received Identity risk
Reply from unsupported alphanumeric sender path no inbound possible capability limitation Must be declared by adapter

A reply is often stronger awareness evidence than a delivery receipt, but it still may not prove that the intended participant acted unless phone-number ownership and context are sufficient for the scenario.

Scenario SMS assessment Normalized event Notes
Consent recorded channel usable adapter metadata or evidence May be required before send
Consent missing fail.consent_missing notification.attempt.rejected_by_adapter Local policy block
STOP received fail.opted_out notification.channel.unsubscribe_received + suppression Channel blocked
START received channel may be restored notification.channel.suppression_removed Provider/country dependent
HELP received neutral/support event interaction.reply_received May trigger help response
Manual suppression fail.suppressed notification.channel.suppression_added Operator action
Provider suppression fail.suppressed notification.channel.suppression_added Provider-managed
Suppression removed active/unknown notification.channel.suppression_removed Channel may become usable

For non-marketing or legally required notifications, opt-out semantics must be scenario-specific. sms-connect records the event; coordination-engine decides whether SMS remains permissible, whether fallback is needed, or whether manual handling is required.

12. Adapter-to-Coordination Mapping

12.1 Core Mapping Table

SMS-native event SMS assessment coordination-engine event Coordination interpretation
message created undef.pending notification.attempt.created Attempt exists
render failed fail.message_too_long_or_invalid notification.attempt.rejected_by_adapter Notification failed before send
consent block fail.consent_missing notification.attempt.rejected_by_adapter Local policy block
suppression hit fail.suppressed notification.channel.suppression_added Channel blocked
adapter accepted undef.pending notification.attempt.accepted_by_adapter Work accepted
adapter rejected adapter-specific fail notification.attempt.rejected_by_adapter Attempt failed
provider accepted undef.provider_accepted_only notification.attempt.accepted_by_provider Weak send evidence
provider rejected fail.provider_rejected notification.attempt.rejected_by_provider Strong attempt failure
provider queued undef.queued notification.attempt.queued Pending
dispatched undef.dispatched notification.attempt.accepted_by_provider + metadata Sent downstream
carrier accepted undef.carrier_accepted_only notification.endpoint.accepted Medium endpoint evidence
buffered undef.buffered notification.endpoint.deferred Pending
delivered success.delivered notification.endpoint.accepted with delivered metadata Strong endpoint evidence, not human proof
undelivered fail.delivery_failed notification.endpoint.rejected_permanent or temporary Use reason code
failed fail.delivery_failed notification.endpoint.rejected_permanent Strong final failure
rejected fail.carrier_rejected notification.endpoint.rejected_permanent Strong final failure
expired fail.expired or undef.expired_unknown notification.endpoint.unknown or rejected Depends on reason
unknown undef.dlr_unknown notification.endpoint.unknown Unclear outcome
inbound reply success.reply_received interaction.reply_received Strong awareness evidence
ACK reply success.acknowledgement_reply_received interaction.acknowledgement_recorded Result evidence if policy accepts
STOP fail.opted_out notification.channel.unsubscribe_received Channel constraint
START active/unknown notification.channel.suppression_removed Channel may be usable
tracked link clicked undef.link_clicked_identity_uncertain interaction.unverified_actor_interaction Identity uncertain

12.2 Coordination Undef Subclasses

coordination-engine may derive these participant uncertainty classes from SMS evidence:

undef.pending
undef.technical_acceptance_only
undef.endpoint_acceptance_only
undef.delivered_but_awareness_unproven
undef.no_signal
undef.weak_positive
undef.identity_uncertain
undef.channel_suspicious
undef.conflicting_evidence
undef.delivery_pending
undef.escalation_required

SMS evidence commonly produces:

undef.pending
undef.endpoint_acceptance_only
undef.delivered_but_awareness_unproven
undef.identity_uncertain
undef.conflicting_evidence

13. Evidence Grading Rules

13.1 Provider Acceptance

event_type: notification.attempt.accepted_by_provider
evidence_grade:
  strength: weak
  actor_certainty: none
  authority_certainty: none
  payload_certainty: low
  interaction_certainty: none
  timing_certainty: medium
  channel_certainty: medium
  non_repudiation_strength: none
notes:
  - Provider accepted message for processing.
  - Does not prove carrier acceptance or handset delivery.

13.2 Carrier Acceptance

event_type: notification.endpoint.accepted
evidence_grade:
  strength: medium
  actor_certainty: none
  authority_certainty: none
  payload_certainty: low
  interaction_certainty: none
  timing_certainty: medium
  channel_certainty: medium
  non_repudiation_strength: low
notes:
  - Downstream carrier or network accepted the message.
  - Does not prove recipient read or understood the message.

13.3 Delivered DLR

event_type: notification.endpoint.accepted
evidence_grade:
  strength: strong
  actor_certainty: none
  authority_certainty: none
  payload_certainty: medium
  interaction_certainty: low
  timing_certainty: high
  channel_certainty: high
  non_repudiation_strength: low
notes:
  - Delivery receipt indicates successful delivery according to provider/carrier semantics.
  - Does not prove human awareness or intended-recipient identity.

13.4 Undelivered / Failed

event_type: notification.endpoint.rejected_permanent
evidence_grade:
  strength: negative
  actor_certainty: none
  authority_certainty: none
  payload_certainty: none
  interaction_certainty: none
  timing_certainty: medium
  channel_certainty: high
  non_repudiation_strength: low
notes:
  - Strong evidence that the SMS channel failed for this attempt.
  - Failure reason should determine retry, fallback, or suppression.

13.5 Buffered / Deferred

event_type: notification.endpoint.deferred
evidence_grade:
  strength: ambiguous
  actor_certainty: none
  authority_certainty: none
  payload_certainty: none
  interaction_certainty: none
  timing_certainty: medium
  channel_certainty: medium
  non_repudiation_strength: none
notes:
  - Message is pending or held for later delivery.
  - Outcome remains uncertain until final DLR, timeout, or expiry.

13.6 Unknown / No DLR

event_type: notification.endpoint.unknown
evidence_grade:
  strength: ambiguous
  actor_certainty: none
  authority_certainty: none
  payload_certainty: none
  interaction_certainty: none
  timing_certainty: low
  channel_certainty: low
  non_repudiation_strength: none
notes:
  - No useful delivery status is available.
  - Policy should decide wait, retry, alternate channel, or manual review.

13.7 Inbound Reply

event_type: interaction.reply_received
evidence_grade:
  strength: strong
  actor_certainty: medium
  authority_certainty: low
  payload_certainty: medium
  interaction_certainty: high
  timing_certainty: high
  channel_certainty: high
  non_repudiation_strength: low
notes:
  - Reply indicates interaction from the phone endpoint.
  - Identity and authority may still require validation.

13.8 Acknowledgement Reply

event_type: interaction.acknowledgement_recorded
evidence_grade:
  strength: strong
  actor_certainty: medium
  authority_certainty: low
  payload_certainty: medium
  interaction_certainty: high
  timing_certainty: high
  channel_certainty: high
  non_repudiation_strength: low
notes:
  - Recipient endpoint replied with an acknowledgement keyword.
  - Whether this satisfies the intended result is scenario-policy dependent.

13.9 Opt-Out

event_type: notification.channel.unsubscribe_received
evidence_grade:
  strength: negative
  actor_certainty: medium
  authority_certainty: low
  payload_certainty: none
  interaction_certainty: high
  timing_certainty: high
  channel_certainty: high
  non_repudiation_strength: low
notes:
  - Phone endpoint opted out or requested no further messages.
  - Future use of the channel may be legally, contractually, or operationally constrained.
event_type: interaction.unverified_actor_interaction
evidence_grade:
  strength: medium
  actor_certainty: low
  authority_certainty: none
  payload_certainty: medium
  interaction_certainty: medium
  timing_certainty: medium
  channel_certainty: medium
  non_repudiation_strength: none
notes:
  - Link was clicked, but actor identity is not proven.
  - Stronger evidence should come from the action surface or identity adapter.

14. Message Timeline API

sms-connect SHOULD expose a message timeline suitable for standalone diagnostics and coordination audit.

SmsMessageTimeline:
  sms_message_id: string
  sms_attempts:
    - sms_attempt_id: string
      provider_name: string
      provider_message_id: string?
      events:
        - SmsTimelineEvent
  segments:
    - SmsSegment
  current_assessment: SmsEvidenceAssessment
SmsTimelineEvent:
  event_id: string
  event_type: string
  occurred_at: timestamp
  source: adapter | provider | carrier | inbound_sms | tracking | operator
  native_event_type: string?
  normalized_event_type: string?
  summary: string
  evidence_grade: EvidenceGrade
  raw_event_ref: string?

15. Adapter Descriptor

sms-connect MUST expose an AdapterDescriptor compatible with AdapterInterfaceSpecification.md v1.0.

adapter_id: sms-connect.default
adapter_name: sms-connect
adapter_version: 1.0.0
adapter_contract_version: 1.0
adapter_types:
  - notification
  - communication
  - interaction
provider_family: sms
provider_name: configurable
deployment_mode: external
supported_channels:
  - sms
supported_endpoint_types:
  - phone_number
  - short_code
  - long_code
  - toll_free
  - alphanumeric_sender_id
supported_actions:
  - action_type: notification.send
    mode: async
    idempotency_required: true
  - action_type: notification.send_reminder
    mode: async
    idempotency_required: true
  - action_type: notification.schedule
    mode: scheduled
    idempotency_required: true
  - action_type: notification.register_tracking_context
    mode: sync
    idempotency_required: true
  - action_type: recipient.suppress
    mode: sync
    idempotency_required: true
  - action_type: recipient.unsuppress
    mode: sync
    idempotency_required: true
emitted_event_types:
  - notification.attempt.created
  - notification.attempt.accepted_by_adapter
  - notification.attempt.rejected_by_adapter
  - notification.attempt.accepted_by_provider
  - notification.attempt.rejected_by_provider
  - notification.attempt.queued
  - notification.attempt.scheduled
  - notification.attempt.delayed
  - notification.endpoint.accepted
  - notification.endpoint.deferred
  - notification.endpoint.rejected_temporary
  - notification.endpoint.rejected_permanent
  - notification.endpoint.unreachable
  - notification.endpoint.unknown
  - notification.channel.unsubscribe_received
  - notification.channel.suppression_added
  - notification.channel.suppression_removed
  - notification.channel.reputation_warning
  - interaction.reply_received
  - interaction.acknowledgement_recorded
  - interaction.unverified_actor_interaction
  - system.provider.degraded
  - system.provider.unavailable
evidence_profile:
  strongest_evidence_level: medium_to_strong
  can_prove_human_awareness: false
  can_prove_payload_delivery: false
  can_prove_identity: false
identity_profile:
  identity_strength: low_to_medium
  authority_strength: none_to_low
limitations:
  - SMS delivery receipts do not prove that the intended human read the message.
  - Some routes do not provide reliable final delivery receipts.
  - Delivered status semantics differ by provider, country, carrier, and route.
  - Phone numbers may be reassigned, shared, forwarded, or unavailable.
  - Link clicks do not prove actor identity.
  - SMS content may be filtered by carriers or blocked by compliance rules.
  - Alphanumeric sender IDs may not support inbound replies.

16. Action Request Handling

16.1 notification.send

notification.send sends a new SMS notification.

Required fields:

request_id
action_type
coordination_case_id
participant_id
target_endpoint
content or template_ref
tracking_context
idempotency_key
requested_at

Example:

request_id: req_001
action_type: notification.send
coordination_case_id: case_123
participant_id: participant_456
channel: sms
target_endpoint:
  endpoint_type: phone_number
  value: "+491701234567"
template_ref: secure-document-sms-reminder
variables:
  portal_link: https://portal.example.com/access/abc
tracking_context:
  correlation_id: corr_789
  coordination_case_id: case_123
  participant_id: participant_456
  notification_id: notif_001
  payload_id: payload_777
idempotency_key: case_123:participant_456:sms:notif_001
requested_at: 2026-01-01T12:00:00Z

16.2 Action Result

The adapter returns:

request_id: req_001
adapter_id: sms-connect.default
accepted: true
action_state: accepted
adapter_operation_id: smsop_001
provider_operation_id: providerop_001
initial_events:
  - event_type: notification.attempt.accepted_by_adapter
received_at: 2026-01-01T12:00:01Z

The result does not prove the SMS was delivered or read.

17. Provider Abstraction

sms-connect SHOULD support a provider abstraction layer.

Provider integration responsibilities:

  • send SMS messages
  • store provider message IDs
  • verify webhooks
  • ingest delivery receipts
  • normalize provider statuses
  • parse error codes
  • handle opt-out events
  • handle inbound replies
  • expose provider health
  • expose route/country/sender limitations

Provider model:

SmsProvider:
  provider_name: string
  provider_account_ref: string
  supported_features:
    - sending
    - delivery_receipts
    - inbound_sms
    - opt_out_handling
    - sender_pools
    - short_codes
    - toll_free
    - alphanumeric_sender_id
    - scheduled_send
    - status_callbacks
  event_mapping_ref: string
  configuration_ref: string

The first implementation MAY use a simulated provider. Real providers SHOULD be added behind this abstraction.

18. Native Provider Event Mapping

The adapter MUST support provider-specific mapping files or code modules.

Common provider-native status groups:

accepted
queued
scheduled
sending
sent
dispatched
carrier_accepted
buffered
delivered
undelivered
failed
rejected
expired
unknown
deleted
opted_out
inbound

Important mapping rule:

Provider delivered events MUST be interpreted carefully.

For SMS, delivered usually means a provider or downstream network reports successful delivery according to its route-specific semantics. It SHOULD map to:

notification.endpoint.accepted

with delivery metadata and strong endpoint evidence, but not to coordination result success unless the scenario policy explicitly accepts SMS DLR as sufficient.

19. Delivery Receipt Classification

sms-connect SHOULD classify delivery receipts into structured outcomes.

SmsDeliveryReceipt:
  provider_name: string
  provider_message_id: string
  provider_status: string
  provider_error_code: string?
  provider_error_text: string?
  carrier_status: string?
  carrier_error_code: string?
  occurred_at: timestamp
  final: boolean?
  retryable: boolean?
  classification:
    - delivered
    - accepted
    - buffered
    - deferred
    - expired
    - failed
    - rejected
    - unknown
    - unknown_subscriber
    - unavailable_subscriber
    - unreachable_subscriber
    - blocked
    - filtered
    - invalid_number
    - route_unavailable
    - sender_not_allowed
    - content_not_allowed
    - regulatory_rejected
    - temporary_network_error
    - provider_error

Suggested mappings:

DLR class SMS assessment Normalized event
delivered success.delivered notification.endpoint.accepted
accepted undef.carrier_accepted_only notification.endpoint.accepted
buffered undef.buffered notification.endpoint.deferred
deferred undef.deferred notification.endpoint.deferred
expired fail.expired or undef.expired_unknown notification.endpoint.unknown or rejected
failed fail.delivery_failed notification.endpoint.rejected_permanent
rejected fail.carrier_rejected notification.endpoint.rejected_permanent
unknown undef.dlr_unknown notification.endpoint.unknown
unknown_subscriber fail.unknown_subscriber notification.endpoint.rejected_permanent
unavailable_subscriber undef.deferred or fail.unavailable_subscriber temporary or permanent by provider code
filtered fail.filtered_by_carrier notification.endpoint.rejected_permanent
sender_not_allowed fail.sender_not_allowed notification.attempt.rejected_by_provider or endpoint rejection
regulatory_rejected fail.policy_rejected notification.endpoint.rejected_permanent
temporary_network_error undef.deferred notification.endpoint.rejected_temporary

sms-connect SHOULD maintain or integrate with a consent and suppression model.

SmsConsent:
  endpoint_ref: EndpointRef
  consent_state: opted_in | opted_out | unknown | not_required | disputed
  consent_scope: global | tenant | sender_identity | campaign | coordination_case | purpose
  consent_source: form | sms_keyword | contract | import | operator | external_system | unknown
  consent_acquired_at: timestamp?
  consent_evidence_ref: string?
  expires_at: timestamp?
SmsSuppression:
  endpoint_ref: EndpointRef
  suppression_type: opt_out | hard_failure | complaint | manual | provider_policy | consent_missing | unknown
  scope: global | tenant | sender_identity | campaign | coordination_case | purpose
  reason: string?
  source: provider | adapter | operator | participant | policy
  created_at: timestamp
  expires_at: timestamp?

Suppression should produce evidence:

notification.channel.suppression_added
notification.channel.suppression_removed
notification.channel.unsubscribe_received

coordination-engine decides whether suppression means participant failure, channel failure, alternate channel selection, or manual review.

21. Sender Identity and Campaign Model

SMS deliverability and compliance often depend on sender identity and campaign registration.

sms-connect SHOULD support sender identity metadata.

SmsSenderIdentity:
  sender_identity_id: string
  sender_type: long_code | short_code | toll_free | alphanumeric_sender_id | sender_pool | unknown
  sender_value: string?
  country_scope:
    - string
  registration_state: unknown | not_required | pending | registered | rejected | expired
  use_case: transactional | informational | marketing | verification | alert | mixed | unknown
  brand_ref: string?
  campaign_ref: string?
  provider_account_ref: string?
  throughput_profile_ref: string?
  limitations:
    - string

Examples of limitations:

inbound_replies_not_supported
country_not_supported
marketing_not_allowed
registration_required
low_throughput
content_filtering_risk

22. Message Content, Encoding, and Segmentation

sms-connect SHOULD analyze message content before sending.

SmsContentAnalysis:
  body_length: integer
  encoding: gsm7 | ucs2 | binary | unknown
  segment_count: integer
  per_segment_limit: integer
  contains_url: boolean
  contains_tracking_link: boolean
  contains_opt_out_text: boolean
  contains_non_gsm_characters: boolean
  estimated_cost_units: number?
  warnings:
    - string

Potential warnings:

message_requires_multiple_segments
unicode_reduces_segment_capacity
tracking_link_may_increase_length
message_missing_required_opt_out_text
content_filtering_risk
sender_identity_not_allowed_for_replies

Content analysis should not by itself determine coordination success, but it is important for cost, reliability, compliance, and diagnostics.

SMS has no native open tracking. Link tracking may provide interaction evidence if a tracked URL is included.

SmsLinkClickEvent:
  sms_message_id: string
  link_id: string
  occurred_at: timestamp
  url: string
  ip_address: string?
  user_agent: string?
  scanner_classification: none | suspected | likely | confirmed | unknown
  confidence: low | medium | high

Possible classifications:

human_like_click
scanner_click
link_preview_fetch
unverified_click
unknown_click

The adapter SHOULD classify link clicks conservatively.

A click is not identity-bound unless paired with trusted identity evidence from the action surface.

24. Inbound Reply Model

sms-connect SHOULD support inbound SMS where the sender type and route support replies.

SmsInboundMessage:
  inbound_message_id: string
  provider_name: string
  provider_message_id: string?
  from_endpoint: SmsEndpoint
  to_endpoint: SmsEndpoint
  received_at: timestamp
  body_text: string
  keyword_classification: none | opt_out | opt_in | help | acknowledgement | free_text | unknown
  correlation: CorrelationContext?
  raw_event_ref: string?

Keyword classifications:

STOP / UNSUBSCRIBE / CANCEL / END / QUIT
START / UNSTOP
HELP / INFO
YES / OK / ACK / CONFIRM
NO / DECLINE

Actual keyword handling should be configurable by country, provider, language, sender identity, and scenario.

25. Phone Endpoint Quality

sms-connect SHOULD maintain phone endpoint quality signals.

SmsEndpointQuality:
  endpoint_ref: EndpointRef
  e164_valid: boolean?
  country_code: string?
  number_type: mobile | landline | voip | toll_free | unknown
  reachable: boolean?
  carrier_name: string?
  ported: boolean?
  roaming: boolean?
  consent_state: string?
  suppression_state: string?
  last_provider_acceptance_at: timestamp?
  last_carrier_acceptance_at: timestamp?
  last_delivered_at: timestamp?
  last_failed_at: timestamp?
  last_opt_out_at: timestamp?
  last_reply_at: timestamp?

Endpoint quality may be emitted as diagnostics but should not by itself create coordination success.

26. Channel Health

sms-connect SHOULD expose channel health.

SmsChannelHealth:
  sender_identity_ref: string
  provider_account_ref: string?
  country_scope: string?
  status: healthy | degraded | failing | unknown
  registration_status: registered | pending | rejected | expired | not_required | unknown
  route_status: healthy | degraded | unavailable | unknown
  deliverability_status: good | warning | poor | unknown
  opt_out_rate: number?
  failure_rate: number?
  unknown_rate: number?
  filtering_rate: number?
  provider_degradation:
    - string

Health-related normalized events:

notification.channel.reputation_warning
system.provider.degraded
system.provider.unavailable
system.adapter.health_changed

27. Security Requirements

sms-connect MUST:

  • protect provider credentials
  • verify provider webhooks where possible
  • validate inbound provider event authenticity where possible
  • preserve idempotency
  • prevent duplicate sends for repeated idempotency keys
  • protect opt-out and consent records
  • avoid leaking phone numbers in logs where possible
  • avoid exposing tracking tokens unnecessarily
  • sanitize inbound SMS bodies before processing
  • support tenant or sender separation where applicable

28. Privacy Requirements

sms-connect SHOULD:

  • store message content only when necessary
  • support metadata-only mode
  • support raw event redaction
  • support configurable retention of raw provider events
  • store endpoint references instead of full phone numbers where possible
  • support masking of phone numbers
  • support deletion or anonymization workflows
  • separate operational diagnostics from coordination evidence
  • avoid unnecessary retention of link-click metadata
  • allow link tracking to be disabled

29. Reliability Requirements

sms-connect MUST support:

  • idempotent send requests
  • duplicate webhook event detection
  • out-of-order event handling
  • late DLR handling
  • retryable provider failures
  • non-retryable provider failures
  • provider timeout handling
  • correlation preservation
  • dead-letter handling for unprocessable events
  • explicit timeout/expiry handling for missing final DLRs

Late events MUST be preserved.

Example:

Provider accepted at 10:00
No DLR by 12:00
Participant unresolved at 14:00
Delivery receipt arrives at 18:00

The late DLR must still be recorded and emitted as evidence.

30. Raw Event Preservation

sms-connect SHOULD preserve raw provider events or references to them.

RawSmsEventRef:
  raw_event_id: string
  provider_name: string
  storage_ref: string?
  received_at: timestamp
  redacted: boolean

Normalized events should reference raw event data where available:

raw_event_ref: raw_sms_event_123

31. Minimal API Surface

sms-connect SHOULD expose a headless API.

31.1 Adapter Contract API

Required conceptual operations:

GET /adapter/descriptor
GET /adapter/health
POST /adapter/actions
POST /adapter/events/provider
GET /adapter/events
GET /adapter/messages/{id}/timeline
GET /adapter/messages/{id}/assessment

The actual transport may differ, but these conceptual operations should exist.

31.2 Standalone API

Useful standalone operations:

POST /sms/send
GET /sms/messages/{id}
GET /sms/messages/{id}/timeline
GET /sms/messages/{id}/assessment
GET /sms/endpoints/{id}/quality
POST /sms/suppressions
DELETE /sms/suppressions/{id}
POST /sms/consents
GET /sms/channel-health
GET /sms/content/analyze

32. Example End-to-End Flows

32.1 Secure Document Reminder

  1. coordination-engine creates a coordination case.
  2. Email notification remains unresolved after threshold.
  3. Policy engine selects SMS fallback.
  4. coordination-engine sends notification.send to sms-connect.
  5. sms-connect validates consent, suppression, sender identity, content, and segmentation.
  6. Provider accepts the SMS.
  7. sms-connect emits notification.attempt.accepted_by_provider.
  8. Carrier reports delivery.
  9. sms-connect emits notification.endpoint.accepted with delivered metadata.
  10. Recipient clicks link.
  11. sms-connect emits interaction.unverified_actor_interaction.
  12. Recipient authenticates in portal.
  13. portal-connect emits identity.actor_authenticated.
  14. Recipient downloads document.
  15. portal-connect emits delivery.payload.downloaded.
  16. coordination-engine marks participant complete.

SMS contributed stronger notification evidence than email, but the portal event closes the result.

32.2 Undelivered SMS and Alternate Channel

  1. sms-connect sends SMS.
  2. Provider accepts the message.
  3. Carrier returns unknown subscriber.
  4. sms-connect emits notification.endpoint.rejected_permanent.
  5. coordination-engine marks SMS channel failed for that participant.
  6. Policy engine selects alternate channel or manual review.

32.3 SMS Acknowledgement

  1. coordination-engine sends alert via SMS.
  2. Carrier reports delivery.
  3. Participant replies ACK.
  4. sms-connect emits interaction.acknowledgement_recorded.
  5. If scenario policy accepts SMS acknowledgement, coordination-engine marks the participant as acknowledged.
  6. If stronger identity is required, the participant remains incomplete until identity-bound evidence is provided.

32.4 Opt-Out Handling

  1. Participant replies STOP.
  2. sms-connect records opt-out and adds suppression.
  3. sms-connect emits notification.channel.unsubscribe_received and notification.channel.suppression_added.
  4. coordination-engine updates channel viability.
  5. Policy engine selects fallback channel or manual review depending on scenario.

33. Provider Implementation Guidance

The first real provider integration SHOULD be selected based on:

  • delivery receipt quality
  • clear status callbacks
  • error-code detail
  • inbound SMS support
  • opt-out handling support
  • sender identity support
  • country coverage
  • webhook security
  • correlation metadata support
  • cost and local availability
  • compatibility with transactional and high-assurance notifications

The implementation SHOULD avoid hardcoding provider semantics into the core SMS model.

Provider-specific modules should map to the SMS-native model first, then to normalized coordination events.

Provider event
→ sms-native event
→ SmsEvidenceAssessment
→ EvidenceEvent for coordination-engine

34. Message Stream Separation

sms-connect SHOULD support sender identities, campaign scopes, and message streams.

Recommended streams:

transactional
notification
legal_or_high_assurance_notice
marketing
verification
system_alert
test

High-assurance or legally relevant notifications SHOULD NOT share th sender configuration with marketing traffic unless explicitly accepted by policy.

Stream separation may affect:

  • sender number
  • sender pool
  • short code
  • toll-free number
  • alphanumeric sender ID
  • campaign registration
  • consent scope
  • opt-out scope
  • throughput
  • carrier filtering risk
  • delivery diagnostics

sms-connect does not by itself provide legal proof of delivery, legal notice, acceptance, signature, payment, or contract closure.

It provides evidence from the SMS channel.

Scenario-specific applications and coordination-engine policies may combine SMS evidence with stronger evidence from portal, identity, signature, payment, archive, or manual processes.

The adapter MUST avoid naming technical SMS events in ways that imply legal success.

Use:

notification.endpoint.accepted

Avoid:

recipient_legally_notified
delivery_legally_completed
human_read_confirmed

36. MVP Scope

The first useful version of sms-connect should implement:

  1. Adapter descriptor.
  2. Adapter health endpoint.
  3. notification.send.
  4. Idempotent send request handling.
  5. Simulated provider or one real provider.
  6. SMS message and attempt records.
  7. Provider event ingestion.
  8. Basic delivery receipt classification.
  9. Basic phone endpoint validation.
  10. Basic segmentation and encoding analysis.
  11. Basic opt-out/suppression support.
  12. Basic inbound reply support if provider allows.
  13. Evidence event generation.
  14. Message timeline.
  15. Message assessment.
  16. Mapping to AdapterInterfaceSpecification.md v1.0.

MVP Required SMS Events

notification.attempt.accepted_by_adapter
notification.attempt.rejected_by_adapter
notification.attempt.accepted_by_provider
notification.attempt.rejected_by_provider
notification.attempt.queued
notification.endpoint.accepted
notification.endpoint.deferred
notification.endpoint.rejected_temporary
notification.endpoint.rejected_permanent
notification.endpoint.unknown
notification.channel.unsubscribe_received
notification.channel.suppression_added
interaction.reply_received
interaction.acknowledgement_recorded
interaction.unverified_actor_interaction

MVP Acceptance Criteria

The MVP is acceptable when it can:

  1. Accept a coordination-compatible SMS send request.
  2. Dispatch or simulate an SMS.
  3. Preserve correlation and idempotency.
  4. Ingest or simulate provider delivery receipts.
  5. Produce normalized evidence events.
  6. Classify provider acceptance as weak evidence.
  7. Classify delivered DLR as strong endpoint evidence but not human-awareness proof.
  8. Classify final undelivered/failed/rejected states as negative channel evidence.
  9. Classify unknown/no-DLR cases as unresolved.
  10. Record STOP/opt-out as suppression evidence.
  11. Record inbound replies as interaction evidence.
  12. Provide a message timeline.
  13. Provide an SMS evidence assessment.
  14. Integrate with coordination-engine without overclaiming success.

37. Future Extensions

Potential future capabilities:

  • multi-provider routing
  • provider failover
  • country-specific routing rules
  • sender pool optimization
  • throughput management
  • advanced number lookup
  • number reassignment risk detection
  • HLR or carrier lookup integration where lawful and available
  • advanced opt-in/opt-out workflow
  • advanced keyword routing
  • two-way conversational SMS support
  • natural-language reply classification
  • URL shortening and tracking integration
  • adaptive fallback between email, SMS, push, and voice
  • RCS adapter extension or separate rcs-connect
  • MMS support
  • WhatsApp or messaging-app adapters
  • regulatory diagnostics by country
  • A2P registration diagnostics
  • carrier filtering risk scoring
  • cost forecasting by segment count and country
  • consent evidence archive integration

38. Non-Goals

sms-connect is not:

  • a marketing automation platform
  • a full conversational messaging platform
  • a CRM
  • a full workflow engine
  • a legal notice system by itself
  • a payment system
  • a signature system
  • an identity verification system by itself
  • the owner of coordination case success

It may integrate with such systems or be used by them.

39. Summary

sms-connect models SMS as a useful but still uncertain notification, reminder, and lightweight interaction channel.

Its job is to:

  • send SMS messages
  • ingest provider and carrier delivery receipts
  • classify SMS outcomes
  • normalize SMS evidence
  • manage opt-out and suppression state
  • record inbound replies
  • analyze content, encoding, and segmentation
  • expose endpoint and channel diagnostics
  • integrate cleanly with coordination-engine

The key rule is:

SMS events are evidence, not result satisfaction. sms-connect reports SMS-channel facts and uncertainty. coordination-engine evaluates intended results.