# ADR-020: Independent Enterprise Payment Platform Service (Torbat Pay) | Field | Value | | --- | --- | | Status | Accepted | | Date | 2026-07-27 | | Deciders | Platform Architecture | | Supersedes | — | | Superseded by | — | ## Context Every TorbatYar vertical — Accounting, CRM, Hospitality, Sports Center, Marketplace, Delivery, Experience, Healthcare, Beauty Business, Automation, and future services — needs payment capture without embedding PSP credentials, callback handling, or transaction ledgers inside each service. Tenants require two commercial modes: 1. **Bring Your Own PSP (BYO-PSP)** — connect tenant-owned gateways (ZarinPal, IDPay, NextPay, Pay.ir, Mellat, Parsian, Saman, …). 2. **Torbat Pay Merchant** — Torbat Pay acts as payment facilitator; tenants onboard as sub-merchants under platform settlement rules. TorbatYar already isolates shared platforms as independent services (Communication [ADR-012](ADR-012.md), Loyalty [ADR-011](ADR-011.md), Delivery [ADR-015](ADR-015.md)). Payment capture, PSP routing, verification, and payment-domain ledger must follow the same pattern. Accounting owns financial journals via Posting Engine [ADR-010](ADR-010.md); Payment must never create journal entries locally. International PSP expansion is **not** in current scope but the provider adapter architecture must allow future regions without vertical changes. Commercial product name: **Torbat Pay**. ## Decision 1. Introduce `payment` as an **independent Enterprise Payment Platform service** with sole ownership of `payment_db` ([ADR-001](ADR-001.md)). 2. Permission prefix: `payment.*`. Publish-only domain events: `payment.*`. 3. Row-level multi-tenancy via `tenant_id` ([ADR-003](ADR-003.md)). 4. PSP implementations sit behind **provider protocols/adapters** owned by Payment; verticals never call PSP APIs directly. 5. Consume Accounting, CRM, Loyalty, Communication, Core, and all vertical services **only** via REST API and Events — never shared tables or foreign model imports. 6. Financial journals only through Accounting Posting Engine ([ADR-010](ADR-010.md)). Payment emits settlement/reconciliation **intents**; Accounting posts externally. 7. Customer payment notifications (receipt SMS/email) only through Communication ([ADR-012](ADR-012.md)). 8. Vertical services (Hospitality POS, Marketplace checkout, Sports Center membership, Experience widgets, etc.) hold **commercial context refs only** (`order_ref`, `invoice_ref`, `checkout_session_ref`) and delegate capture to Payment APIs. 9. Implementation phases registered as **`payment-14.0`–`payment-14.10`** in [phase-manifest.yaml](../../ai-framework/phase-manifest.yaml); roadmap in [payment-roadmap.md](../../payment-roadmap.md). Phase numeric **14.x** is the Payment **track** identifier; it is distinct from Beauty Business phases (`beauty-business-14.x`). 10. API port **8012** reserved; service path `backend/services/payment`. 11. UI for checkout, merchant admin, and reconciliation dashboards lives in `frontend/` only ([ADR-002](ADR-002.md)); this service exposes APIs and events. 12. No international PSP implementation in initial HIGH-priority phases; adapter registry and credential schema must be region-aware for future expansion. ## Consequences ### Positive - One reusable payment platform for all current and future TorbatYar services - Enforceable PSP credential isolation and callback verification in one place - BYO-PSP and Torbat Pay Merchant modes without duplicating integration code per vertical - Clear boundary with Accounting (money movement vs financial posting) ### Negative - Additional deployable service and database - Eventual consistency between payment status and vertical order state - PCI scope management for facilitator mode requires operational discipline (documented, not implemented in registration) ### Neutral - Registration (this ADR + manifests) precedes business code; `payment-14.0` implements the scaffold - Loyalty wallet/gift-card money flows remain in Loyalty; Payment handles external PSP money-in only unless explicitly integrated later ## Alternatives Considered 1. Payment subsystem inside Core — rejected (violates business-module boundaries; couples platform billing with tenant commerce payments). 2. Payment tables inside Accounting — rejected (Accounting owns posting semantics, not PSP routing/callbacks). 3. Per-vertical PSP integrations — rejected (duplicates credentials, callbacks, idempotency, and audit across Hospitality/Marketplace/Sports Center). 4. Third-party payment orchestration SaaS only — rejected for primary path (tenant BYO-PSP and facilitator control require owned platform). ## Related Documents - [Payment Roadmap](../../payment-roadmap.md) - [Phase Area — Payment](../../phases/Payment/README.md) - [Module Boundaries](../module-boundaries.md) - [Module Registry — payment](../../module-registry.md#payment) - [Payment Contracts Reference](../../reference/payment-contracts.md) - [Phase Manifest](../../ai-framework/phase-manifest.yaml) - [Service Manifest](../../ai-framework/service-manifest.yaml) - [ADR-001](ADR-001.md) · [ADR-002](ADR-002.md) · [ADR-003](ADR-003.md) · [ADR-006](ADR-006.md) · [ADR-010](ADR-010.md) · [ADR-011](ADR-011.md) · [ADR-012](ADR-012.md) · [ADR-021](ADR-021.md)