Architecture Overview¶
Heka is a single-process FastAPI server that acts as the bridge between WhatsApp Cloud API and an AI conversation agent. It persists all state in a local SQLite database (WAL mode) on a Fly.io volume.
Request flow¶
Meta Cloud API Heka Server External
───────────── ─────────── ────────
┌──────────────────────┐
Webhook POST ──────────────────► meta_webhook.py │
(inbound msg) │ ├─ parse payload │
│ ├─ save MessageRecord │
│ ├─ check ownership │──── human-owned? ──► skip agent
│ ├─ run agent │
│ │ ├─ load context │
│ │ ├─ Claude API ───│──────────► Anthropic
│ │ └─ extract data │
│ ├─ advance pipeline │
│ └─ send response ────│──────────► Meta Graph API
│ │
Status callback ───────────────► meta_status.py │
(sent/delivered/read) │ └─ save StatusRecord │
│ │
│ campaign/router.py │
Operator Console ──────────────► ├─ send-template │──────────► Meta Graph API
(REST API calls) │ ├─ send-template/batch│
│ ├─ campaign CRUD │
│ └─ funnel management│
└──────────────────────┘
Key modules¶
Channels (heka.channels)¶
Abstraction over the WhatsApp Cloud API. The ProviderSender Protocol defines the send interface; MetaSender implements it against the Graph API; FakeMetaSender records calls for testing.
The sender supports: text messages, media messages, template messages (with TEXT, IMAGE, VIDEO, and LOCATION headers), and interactive buttons.
Campaigns (heka.campaigns)¶
Campaign lifecycle management. A campaign definition (campaigns table) has a pipeline of phases. Contacts move through phases based on conversation signals extracted by the AI agent. The CampaignAgent orchestrates the AI response loop per conversation.
Key subsystems:
- Pipeline — state machine for contact phase transitions with gate validation
- Extraction — Claude-powered structured data extraction from conversations
- Inference — Claude API integration for generating agent responses
- Scheduler — background drip message scheduling and idle timeout handling
Persistence (heka.persistence)¶
SQLite repository with schema auto-migration. Tables include:
| Table | Purpose |
|---|---|
messages |
All inbound/outbound messages with wamid |
message_statuses |
Delivery status callbacks (sent/delivered/read/failed) |
contacts |
Contact profiles with wa_id |
contact_events |
Append-only event log per contact |
contact_profile |
Structured profile data (name, email, etc.) |
campaigns |
Campaign definitions with pipeline_json |
campaign_sends |
Campaign execution records |
campaign_contact_phase |
Contact position in campaign funnel |
ownership_events |
Human/agent ownership transitions |
conversation_summaries |
AI-generated conversation summaries |
segments |
Contact segmentation definitions |
templates |
WhatsApp template metadata cache |
tenant_context |
Tenant-specific agent configuration |
Conversations (heka.conversations)¶
Message send/receive endpoints, conversation timeline, and ownership management. The ConversationGuard enforces ownership rules: when a contact is human-owned, the AI agent does not respond.
Handoff (heka.handoff)¶
Protocol for transferring conversations between AI agent and human operators. Supports accept, release, and automatic idle timeout (30 min with no operator activity).
Data flow invariants¶
- Every inbound message creates a
MessageRecordbefore any processing - Every outbound message creates a
MessageRecordwithwamidfor delivery tracking - Status webhooks correlate to messages via
wamid— no orphan statuses - Contact phase transitions are gated by the campaign pipeline state machine
- Human ownership blocks AI responses until explicitly released
contact_eventsis append-only — updates and deletes trigger errors