Programmable Messaging API  ·  View 12 of 22  ·  Data

Data Model

Message, attempt, receipt, consent — and the nullable foreign key that is the point of the view.

Editable source SVG draw.io All views
tenant tenant_id PK plan entitlement_mps residency_region credit_balance sender_identity sender_id PK tenant_id FK -> tenant type long|short|alpha|toll registrations jsonb throughput_ceiling route route_id PK channel jurisdiction provider price_per_segment window_mps consent_event consent_event_id PK tenant_id FK -> tenant destination_hash sender_id FK -> sender state granted|withdrawn evidence recorded_at message message_id PK tenant_id FK -> tenant client_reference UQ per tenant destination_hash sender_id FK -> sender channel_requested traffic_class ttl_expires_at segments_quoted accepted_at attempt attempt_id PK message_id FK -> message seq route_id FK -> route provider_reference submit_outcome segments_charged submitted_at message_body body_id PK message_id FK -> message object_uri kms_key purge_after receipt receipt_id PK attempt_id FK -> attempt NULLable provider_reference carrier_status carrier_reason carrier_timestamp received_at message_state message_id PK FK -> message state accepted..unknown terminal_at derived_from_attempt // projection, not authority inbound_message inbound_id PK route_id FK -> route provider_reference UQ per route sender_id FK -> sender keyword_actioned received_at rated_usage_event usage_event_id PK attempt_id FK -> attempt tenant_id FK -> tenant route_id FK -> route segments amount 1 : N at submit 1 : N 1 : N 1 : N 1 : N 1 : 1 1 : 0..1 1 : N 1 : 1 Data Model — Message, Attempt, Receipt, Consent receipt.attempt_id is nullable on purpose: an uncorrelatable receipt is kept, not dropped. v 1.0 · owner Integration Platform Architecture

Decisions

  • receipt.attempt_id is nullable on purpose: a receipt that correlates to nothing is kept as evidence rather than discarded as noise.
  • message_state is a projection keyed by message, not a column on message, so no receipt can update truth in place.
  • client_reference is unique per tenant, which makes idempotency a schema property rather than application discipline.

Assumptions

  • Destinations are stored as hashes outside the body store so that consent can be evaluated without reading content.
  • One rated usage event per attempt, carrying the route and segment count that produced the charge.

Deliberate omissions

  • Template, media and campaign entities, and the tenant-credential tables; they do not change the shape of the lifecycle.