Outpost logoOutpost Docs

How Outpost Fits Together

Every component of Outpost and how they relate to each other.

Outpost is built from a small set of components. This page is the system map: what each component is, and - more importantly - how they relate.

The two hierarchies

Outpost organizes data along two independent hierarchies that meet at the message.

The ownership hierarchy answers "who is sending?" Tenants own projects; projects own API keys and webhook configs. Every authenticated request is scoped by this chain.

The grouping hierarchy answers "what is being sent?" Campaigns group communications; communications group messages; each message records its individual send attempts.

The Phone sits outside both hierarchies. Phones are global - the same +15551234567 is a single record shared by every tenant that messages it, because opt-out is a regulatory commitment to the phone's owner, not to any one tenant.

The full entity map

How to read this:

  • A Message is the center of the system. It belongs to a tenant/project (ownership), optionally to a communication/campaign (grouping), and always targets a phone.
  • Events are the immutable audit trail. Message events track the message lifecycle; phone events track phone state changes (opt-outs, validation failures).
  • Webhooks are how events leave Outpost. A project's webhook configs subscribe to event types; matching events produce delivery attempts.
  • Stats are derived counters, updated asynchronously when messages settle or phones change state. They are a read model - messages, phones, and events remain the source of truth.

How a message flows through the system

The runtime picture: components that do work, connected by queues.

  1. The API validates each recipient (format, duplicates, validity, opt-out), creates the message, and queues it.
  2. The send worker runs preflight checks and submits to AWS End User Messaging.
  3. AWS sends back delivery receipts; the DLR worker updates the message, settles it or requeues it for retry.
  4. The two-way worker handles inbound replies - STOP/START/HELP keywords drive opt-out state on the phone.
  5. Every DynamoDB write flows through streams to the stream worker, which updates stats and fans out webhook deliveries.

Workers and queues are covered in detail in Workers & Background Processing.

Component index

ComponentOne-line summary
Tenants & ProjectsOwnership and configuration: who sends, with what settings
API KeysAuthentication; admin keys vs tenant-scoped keys
MessagesOne SMS with full lifecycle tracking; the core entity
Phones & Opt-OutGlobal phonebook, validation, regulatory opt-out
Communications & CampaignsOptional grouping layers; deduplication and rollups
EventsImmutable audit trail for messages and phones
WebhooksPush event notifications to downstream systems
StatsPre-aggregated counters powering dashboards
WorkersThe async machinery: send, DLR, two-way, stream, webhook
Cost ModelHow per-attempt carrier costs roll up

On this page