Billing Service — Service Overview
Status: populated Owner: Platform Engineering + Finance Last updated: 2026-04-18 Companion: DOMAIN_MODEL · API_CONTRACTS · EVENT_SCHEMAS · ADR-0001 Kong
1. Purpose
billing-service is the authoritative source of truth for revenue, margin, and invoicing in Ghasi-SMS-Gateway. It:
- Consumes
billing.eventsfrom NATS JetStream (produced bydlr-processor) to record per-message chargeable events. - Applies versioned pricing rules — per-segment or flat-per-message — keyed by
(accountTier, operatorId, direction, currency). - Models operator costs alongside customer pricing to compute per-message margin.
- Generates monthly invoices via a scheduled cron: PDF rendered from templates, stored in S3-compatible object storage.
- Exposes an admin/internal REST API (via Kong) for pricing CRUD, operator cost CRUD, invoice list/download, and usage queries.
- Publishes
billing.invoice.generatedNATS event after each invoice is finalized.
2. Bounded Context
Revenue & Finance — authoritative owner of all monetization data. Classified as Core (financial correctness is a business-critical requirement; incorrect billing directly affects revenue and contractual SLAs).
3. Responsibilities
| Area | What billing-service owns |
|---|---|
| Chargeable event ingestion | Consumes billing.events, stores billing_events, deduplicates via messageId |
| Pricing engine | Resolves applicable pricing_tables row; computes customerPrice per message/segment |
| Operator cost tracking | Resolves operator_costs row; computes operatorCost; derives margin |
| Usage aggregation | Increments usage_summaries (hourly/daily buckets) for query efficiency |
| Invoice generation | Monthly cron: aggregates usage, renders PDF, stores to S3, persists invoices record |
| Invoice publication | Publishes billing.invoice.generated NATS event post-persist |
| REST API | Pricing CRUD, operator cost CRUD, invoice list/download, usage query (admin/internal, via Kong) |
| Multi-currency support | USD default; currency field on pricing_tables; FX rate applied at event time |
| Pricing cache | Redis TTL-60s cache for hot pricing lookups |
4. Non-Responsibilities
| Area | Owner |
|---|---|
| DLR correlation and event production | dlr-processor |
| SMS send decision / routing | sms-orchestrator + routing-engine |
| Customer-facing invoice UI | customer-portal (reads via API) |
| Payment collection / card processing | External payment gateway (future) |
| Webhook delivery to customers | webhook-dispatcher |
| Auth enforcement at Kong | Kong + auth-service |
5. Dependencies
| Dependency | Kind | Purpose |
|---|---|---|
NATS JetStream (billing.events) | Event bus (consumer) | Ingest chargeable events from dlr-processor |
NATS JetStream (billing.invoice.generated) | Event bus (producer) | Notify downstream on invoice finalization |
PostgreSQL (schema billing) | Data store | All billing tables |
| Redis | Cache | Pricing lookup cache, TTL 60s |
| S3-compatible object store | Storage | Rendered invoice PDFs |
| Kong Gateway | Upstream (HTTP) | Proxies admin/internal REST API |
| auth-service | HTTP (via Kong headers) | JWT claims for account/tenant context |
6. High-Level Flow
7. Key Design Decisions
| Decision | Rationale | Trade-off |
|---|---|---|
Idempotent event ingestion on messageId | Prevents double-billing on NATS redelivery | Requires PG INSERT ... ON CONFLICT DO NOTHING |
Versioned pricing_tables (not point-in-time snapshot) | Allows retroactive pricing corrections within a billing period for agreed adjustments | Must specify effectiveFrom/effectiveTo carefully |
| Redis pricing cache (TTL 60s) | Pricing lookups are hot and read-heavy; avoids PG pressure | 60s stale window acceptable; pricing changes are rare |
| Usage summary pre-aggregation | Invoice generation queries pre-aggregated buckets rather than raw event table | Extra write on ingest; saves order-of-magnitude on invoice query |
| Monthly cron invoice, not real-time | Standard B2B billing cadence; simplifies deferred FX rates | Customers cannot self-serve mid-month subtotals easily (usage query API bridges this) |
| S3 PDF storage, not PG BYTEA | PDF sizes (100 KB–5 MB); keeps PG lean | Requires S3 availability for download; presigned URL approach avoids proxy |
8. Status
Design approved. Implementation gated on dlr-processor publishing billing.events (see EVENT_SCHEMAS) and S3 bucket provisioning. See SERVICE_READINESS for gate checklist.