Skip to main content

Database Schema Reference

Tables Summary​

TableTenant ScopeKey IndexesPurpose
VendorRootplanTypeTenant account
UservendorIdvendorId, emailPlatform users
WabaAccountPlatformisShared, wabaIdShared and dedicated Meta WABA accounts
PhoneNumberWABAwabaId, phoneNumberIdWhatsApp sender numbers
ContactvendorIdvendorId, mobileTenant contacts
MessageLogvendorIdvendorId, phoneNumberId, wabaId, campaignId, status, createdAtMessage audit, queue, and analytics
CampaignvendorIdvendorId, status, scheduledAtBulk messaging campaigns
WalletvendorIdvendorIdTenant balance
TransactionwalletIdwalletId, type, createdAtBilling ledger
TemplatevendorId, optional wabaIdvendorId, wabaId, metaTemplateId, statusVendor and WABA templates
WebhookvendorIdvendorId, eventTypeEvent subscriptions
ApiLogvendorIdvendorId, endpoint, createdAtAPI audit log

Enum Reference​

EnumValues
PlanTypeSHARED, DEDICATED
RoleADMIN, STAFF, USER
MessageStatusQUEUED, SENT, DELIVERED, READ, FAILED
MessageDirectionINBOUND, OUTBOUND
CampaignStatusDRAFT, QUEUED, PROCESSING, COMPLETED, FAILED
TransactionTypeCREDIT_RECHARGE, DEBIT_MESSAGE, REFUND

Unique Constraints​

ConstraintScopePurpose
User.emailPlatformLogin identity
WabaAccount.wabaIdPlatformMeta WABA identity
PhoneNumber.phoneNumberIdPlatformMeta phone number identity
Contact(vendorId, mobile)VendorOne contact number per tenant
MessageLog.waMessageIdPlatformMeta message identity
MessageLog(vendorId, idempotencyKey)VendorPer-tenant idempotent requests
Wallet.vendorIdPlatformOne wallet per vendor
Template.metaTemplateIdPlatformMeta template identity

Foreign Keys​

Cascade Deletes​

Vendor -> User, Contact, Campaign, MessageLog, Template, Webhook, Wallet
WabaAccount -> PhoneNumber
Wallet -> Transaction

Set Null Deletes​

Vendor.dedicatedWabaId -> WabaAccount.id
Template.wabaId -> WabaAccount.id
MessageLog.contactId -> Contact.id
MessageLog.campaignId -> Campaign.id

Restricted / Default Deletes​

MessageLog.phoneNumberId -> PhoneNumber.id uses Restrict
MessageLog.wabaId -> WabaAccount.id uses default behavior
ApiLog.vendorId -> Vendor.id uses default behavior

MessageLog Query Indexes​

IndexUse
vendorIdTenant isolation
phoneNumberIdPhone-specific history
wabaIdWABA analytics
campaignIdCampaign delivery analytics
statusState filters
createdAtTime-range scans
waMessageIdMeta webhook lookup
recipientMobileRecipient audit lookup
recipientMobile, vendorIdTenant recipient history
sourceSource analytics
priorityQueue ordering
vendorId, createdAtTenant timeline
vendorId, status, createdAtTenant status timeline
phoneNumberId, createdAtSender timeline
wabaId, createdAtWABA timeline
campaignId, statusCampaign status counts
nextRetryAtRetry worker pickup
status, priority, nextRetryAtQueue worker scan

Common Queries​

SELECT *
FROM message_log
WHERE vendor_id = $1
ORDER BY created_at DESC
LIMIT 100;
SELECT *
FROM message_log
WHERE vendor_id = $1
AND idempotency_key = $2;
SELECT status, COUNT(*)
FROM message_log
WHERE campaign_id = $1
GROUP BY status;
SELECT *
FROM message_log
WHERE status = 'QUEUED'
AND (next_retry_at IS NULL OR next_retry_at <= NOW())
ORDER BY priority DESC, created_at ASC
LIMIT 500;