Receipt events
“Receipt” inside Active Reach covers two related but distinct things:
- Channel delivery receipts — the
sent/delivered/opened/clicked/failedcallbacks that channel providers fire after a message goes out. These are PASSIVE for MAU classification. - Bill receipts — customer purchase records written to the
unified
bill_receiptstable by Active Bill, the always-on 7th Active product.
Both are documented below.
1. Channel delivery receipts
When Active Reach sends a message, the channel provider reports back delivery status — “delivered”, “bounced”, “opened”, etc. These are delivery receipt events.
Active Reach sends message
↓
Channel provider (WhatsApp, SendGrid, Twilio, MSG91, etc.)
↓
Provider fires webhook to Active Reach
↓
Event ingress processes and normalizes
↓
Receipt event appears in:
- Contact timeline (workspace-scoped via __org__ sentinel or workspace_id)
- Campaign analytics
- Live events stream
- Outbound webhooks (if subscribed) — see /developers/webhooks/event-typesThe canonical event name on the bus is channel_delivery_status, plus
dot-namespaced per-channel variants (email.delivered,
whatsapp.read, etc.). All are classified PASSIVE and excluded from
MAU.
Per-channel statuses
| Status | When it fires |
|---|---|
sent | Message accepted by WhatsApp servers |
delivered | Message delivered to the recipient’s device |
read | Recipient opened the conversation (blue ticks) |
failed | Permanent failure (invalid number, blocked, template rejected) |
| Status | When it fires |
|---|---|
sent | Message accepted by the ESP |
delivered | ESP confirmed delivery to recipient’s mail server |
bounced | Hard bounce (invalid address) or soft bounce (mailbox full) |
opened | Recipient opened the email (tracking pixel loaded) |
clicked | Recipient clicked a tracked link |
complained | Recipient marked as spam |
unsubscribed | Recipient clicked the unsubscribe link |
SMS
| Status | When it fires |
|---|---|
sent | Message accepted by the SMS gateway |
delivered | Carrier confirmed delivery to handset |
failed | Permanent failure (invalid number, DND, carrier rejection) |
RCS
| Status | When it fires |
|---|---|
sent | Message accepted by the RCS gateway |
delivered | Message delivered to the device |
read | Recipient opened the message |
failed | Delivery failed (fallback to SMS if configured) |
Push
| Status | When it fires |
|---|---|
sent | Push dispatched to FCM/APNs |
delivered | Device confirmed receipt |
clicked | User tapped the notification |
Normalized payload
Regardless of channel, delivery receipts normalize to a common shape.
Since the workspace-scoped delivery substrate rolled out (2026-05-22),
workspace_id is reliably present — either the brand’s UUID or the
__org__ sentinel for intentionally org-level rows.
{
"type": "delivery",
"status": "delivered",
"message_id": "msg_xyz789",
"campaign_id": "camp_welcome_q2",
"contact_id": "usr_456",
"channel": "whatsapp",
"timestamp": "2026-05-27T10:31:15.000Z",
"provider": "meta",
"workspace_id": "ws_abc123",
"metadata": {}
}Providers carry the workspace_id round-trip via three tiers:
echoed metadata (MSG91 variables, SendGrid custom_args, Razorpay
notes, Cashfree subscription_tags), URL-encoded callback paths (POS,
shipping, Shopify), or a DB lookup fallback (Stripe, Clerk).
2. Bill receipts (Active Bill)
Active Bill is the 7th Active product and the only one that is
always-on. Every tenant has bills the moment any other Active
product fires — Active POS, Active Commerce, Active Chat, Active
Loyalty, Active Rewards, and Active Feedback all generate purchase
records via the unified bill_receipts table.
A short code on the row resolves to the customer-facing web page:
actii.me/b/{short_code}This is the canonical customer bill URL.
Bill PDFs through the CDN
Bill and invoice PDFs serve through media.active-reach.ai (Cloudflare
fronts both the aegis-media and aegis-data-v2 buckets). Customer
surfaces must use the canonical helpers:
canonical_receipt_url(s3_key)— customer bill PDFscanonical_invoice_url(s3_key)— operator GST invoices
Never embed raw E2E presigned URLs in customer surfaces.
Brand canon
The bill PDF wordmark, customer-facing subjects, and the storefront UI
say Active Reach Platform (product) and Active Reach
Intelligence LLP (company). The Aegis name and the AEG/<FY>
invoice series prefix stay in internal code paths, env vars, DB tables,
and the operator-facing invoice series.
Tax line-item rounding
For bundled bills where the gross is the meaningful number (rather
than a per-unit price), TaxInvoiceService requires
quantity = 1 with the back-computed taxable placed into
unit_amount_paise. The substrate ignores any explicit total_paise
on TaxLineItem inputs and recomputes taxable = quantity × unit_amount_paise — so a quantity × unit_amount shape that doesn’t
multiply out to the intended gross silently loses paise.
What’s next
- Webhook event types — subscribe to delivery receipts via outbound webhooks
- MAU classification — why channel callbacks don’t count toward MAU