--- title: PRD - Seller-Owned White-Label Shops and Bots tags: [prd, marketplace, sellers, white-label, telegram, payments, multi-tenant] created: 2026-06-06 status: future-concept --- # PRD - Seller-Owned White-Label Shops and Bots > Status: **Future concept** > Related docs: [[Seller Guide]], [[ShopSettings]], [[RequestTemplate]], [[Telegram Mini App]], [[Payment Provider Adapter Spec]], [[PRD - Direct Address Token Payments via Scanner Balance Watches]], [[Scanner Architecture]] ## Summary Amanat can evolve from a single escrow marketplace into a marketplace operating system for trusted sellers. Today, a seller can own a shop profile, publish request templates, receive buyer requests, and get paid through Amanat payment rails. The future version would introduce a special class of seller, tentatively called a **merchant tenant**, who can run their own branded or no-label storefront on top of Amanat infrastructure. Each merchant tenant gets: - A branded web shop on their own domain or subdomain. - A dedicated Telegram bot and/or Telegram Mini App surface. - Their own shop admin area and configurable frontend theme. - Catalog, checkout, delivery, and payment integrations. - Choice of Amanat escrow payment, direct Amanat payment without escrow, or external payment providers. - Strong data isolation from other merchants while still allowing Amanat to operate scanner, accounting, billing, abuse, and platform support workflows. This turns Amanat into both a public escrow marketplace and a white-label commerce layer for sellers who already have customers, channels, inventory, or private demand. ## Product framing ### Current seller A current seller is an Amanat user with `role = seller`. They appear inside the Amanat marketplace and configure a single [[ShopSettings]] record. Their public shop is still visibly part of Amanat. ### Future merchant tenant A merchant tenant is a higher-trust seller account that owns one or more isolated shop surfaces. Possible tenant tiers: | Tier | Description | Example | | --- | --- | --- | | Hosted seller | Uses an Amanat subdomain and Amanat bot | `seller.amn.gg` | | White-label seller | Uses their own domain and bot, but Amanat remains the operator of record | `shop.example.com` | | Isolated merchant | Uses own domain, own bot, isolated data store or database user, custom integrations | `example.com` + `@ExampleShopBot` | | Enterprise merchant | Dedicated database, strict network isolation, custom accounting contract, managed support | Larger seller or reseller network | The first version should support one shop per merchant tenant. The architecture should not block multi-shop tenants later. ## Goals - Let selected sellers run a branded or no-label storefront without forking the frontend. - Let a seller bring their own domain through either managed nameservers or a CNAME to Amanat. - Let a seller bring their own Telegram bot token so customers interact with the seller's bot, not only Amanat's main bot. - Allow per-tenant catalog, fulfillment, payment, notification, and support integrations. - Keep payment selection flexible: - Amanat escrow with standard buyer/seller protection. - Direct Amanat payment without escrow. - External payment integrations where supported. - Provide tenant admin controls for branding, catalog sync, payment rails, delivery methods, webhook endpoints, users, and reports. - Isolate tenant data as much as possible without losing the platform's ability to scan payments, reconcile ledger events, bill merchants, and investigate abuse. ## Non-goals - Letting arbitrary sellers self-provision white-label shops without platform approval. - Letting tenant-provided code run inside Amanat infrastructure. - Giving tenants direct access to scanner databases, platform ledgers, or other tenants' records. - Allowing tenants to bypass Amanat compliance, abuse, dispute, or payment-safety policies when using Amanat rails. - Building a full Shopify replacement in the first release. ## User stories ### Merchant owner - As a merchant owner, I can connect `shop.mybrand.com` to Amanat so customers see my brand first. - As a merchant owner, I can provide my Telegram bot token and have Amanat serve checkout, order updates, and support flows through my bot. - As a merchant owner, I can choose whether a product uses escrow, direct payment, or an external provider. - As a merchant owner, I can connect my product source, delivery provider, and accounting webhooks. - As a merchant owner, I can see orders, disputes, delivery events, payment status, and billing in my own admin area. ### Buyer - As a buyer, I can buy from the merchant's shop on web or Telegram without needing to understand that Amanat powers the transaction. - As a buyer, I can still get Amanat escrow protection when the merchant chooses escrow. - As a buyer, I can receive order and delivery updates from the merchant's bot or web shop. ### Amanat operator - As an operator, I can approve which sellers become merchant tenants. - As an operator, I can validate domain ownership, bot token ownership, and payment settings. - As an operator, I can restrict risky integrations, suspend tenants, and preserve evidence. - As an operator, I can bill the merchant based on GMV, transaction count, active storefronts, scanner usage, or fixed subscription terms. ## Tenant surfaces ### Web storefront The web storefront should be a tenant-aware version of the Amanat frontend, not a separate fork per seller. Tenant resolution can happen by: 1. Request host, such as `shop.example.com`. 2. Amanat subdomain, such as `seller.amn.gg`. 3. Explicit tenant slug for preview and fallback URLs, such as `amn.gg/t/{tenantSlug}`. The frontend loads a tenant bootstrap payload: ```json { "tenantId": "tenant_123", "shopId": "shop_123", "brand": { "name": "Example Shop", "logoUrl": "https://...", "primaryColor": "#1F6FEB", "supportEmail": "support@example.com" }, "features": { "escrowCheckout": true, "directCheckout": true, "externalPayments": false, "telegramMiniApp": true }, "paymentRails": ["amn_escrow", "amn_direct"], "localeDefaults": ["en", "fa"] } ``` The page shell, catalog, checkout, order tracking, support, and dispute surfaces use this tenant context for API calls and branding. ### Telegram bot and Mini App A merchant tenant can provide a Telegram bot token. Amanat stores the token encrypted and uses it only for that tenant's bot API calls. The merchant bot can support: - Start and deep-link checkout flows. - Catalog browsing. - Cart or request-template checkout. - Order status updates. - Payment instructions. - Delivery confirmation. - Escrow dispute actions where escrow is active. - Support handoff to the merchant or Amanat operator. Tenant Telegram routing should key off the bot token or bot id. A webhook path can be tenant-specific: ```text POST /api/telegram/tenant/:tenantId/webhook/:secret ``` or bot-specific: ```text POST /api/telegram/bots/:botId/webhook/:secret ``` The important boundary is that a webhook update from one bot can never resolve to another tenant's users, orders, or chat state. ## Domain onboarding ### Option A - Amanat-managed DNS The merchant points nameservers to Amanat-managed DNS. Benefits: - Amanat can automate records, TLS, redirects, and subdomains. - Easier support for apex domains like `example.com`. - Cleaner migration and domain health checks. Costs: - Higher trust requirement. - More operator responsibility. - More DNS support burden. ### Option B - Merchant-managed CNAME The merchant creates a CNAME: ```text shop.example.com CNAME tenants.amn.gg ``` Benefits: - Lower trust requirement. - Easy for most subdomain setups. - Merchant keeps control of the rest of the zone. Costs: - Apex domain support needs ALIAS/ANAME or managed DNS. - Merchant must configure records correctly. - More possible DNS/TLS edge cases. ### Domain validation Before activation, Amanat should require at least one proof: - TXT verification record. - CNAME target match. - Nameserver delegation check. - Signed admin approval for high-trust managed DNS onboarding. TLS should be automatically provisioned after validation. A domain remains in `pending`, `active`, `degraded`, `suspended`, or `removed` state. ## Integration model Each merchant tenant can configure integrations through an adapter layer. ```mermaid flowchart LR TenantAdmin["Tenant admin"] Shop["Tenant shop"] API["Tenant-aware Amanat API"] Catalog["Catalog adapters"] Delivery["Delivery adapters"] Payments["Payment adapters"] Scanner["Amanat scanner"] Accounting["Amanat accounting"] External["External providers"] TenantAdmin --> API Shop --> API API --> Catalog API --> Delivery API --> Payments Payments --> Scanner API --> Accounting Catalog --> External Delivery --> External Payments --> External ``` ### Shopping providers Initial catalog sources can be: - Native Amanat request templates. - Manual product and service entries. - CSV import. - Generic HTTP JSON endpoint. - Later: Shopify, WooCommerce, custom ERP, or marketplace feeds. The normalized product model should support: - Product title, description, media, tags, category. - Fixed price, variable price, quote-required price, or buyer-request flow. - Stock state where applicable. - Delivery modes. - Payment rail eligibility. - Escrow policy per product or product group. ### Delivery mechanisms Delivery integrations can start simple: - Manual delivery status updates. - Tracking number and carrier fields. - Digital delivery upload or external link. - Webhook endpoint for delivery updates. Later adapters can support courier APIs, shipping labels, pickup scheduling, proof-of-delivery, and region-based delivery rules. ### Payment integrations Payment integration should extend the provider-adapter direction from [[Payment Provider Adapter Spec]]. Supported payment classes: | Rail | Escrow? | Description | | --- | --- | --- | | `amn_escrow` | yes | Amanat default protected checkout. Buyer pays into Amanat-controlled escrow flow; release/refund follows ledger and dispute rules. | | `amn_direct` | no | Buyer pays through Amanat payment detection, but funds are not held in escrow. Useful for trusted merchants, low-risk products, or merchant-owned liability. | | `external_provider` | optional | Stripe, crypto processor, bank transfer, or custom provider where Amanat records payment evidence but may not custody or release funds. | | `manual_invoice` | optional | Operator or merchant confirms payment manually with required evidence. | For `amn_direct`, the scanner can still be used to detect payment arrival, but the canonical state should be "paid" rather than "escrow funded". The buyer experience must clearly disclose that Amanat escrow protection is not active. ## Tenant isolation strategy The project should support multiple isolation levels so the first release is achievable while enterprise tenants can later buy stronger boundaries. | Level | Data shape | Isolation | Operational cost | Candidate tier | | --- | --- | --- | --- | --- | | Shared tables with `tenantId` | Single database, all tenant-owned rows carry `tenantId` | Good if every query is tenant-scoped and tested | Low | Hosted seller | | Shared database, tenant schema or DB user | Same cluster, separate schema/user grants | Stronger query and permission boundary | Medium | White-label seller | | Dedicated database | Separate database per merchant tenant | Strong tenant boundary and backup/restore unit | High | Isolated merchant | | Dedicated stack | Separate app, DB, Redis, scanner queue, billing bridge | Maximum boundary | Very high | Enterprise merchant | Even at the lowest level, code should treat tenant context as mandatory for tenant-owned records. Recommended baseline: - Add `tenantId` to tenant-owned entities. - Enforce tenant scoping in service-layer repositories. - Add database indexes by `tenantId`. - Use tenant-aware auth claims and session context. - Add automated tests for cross-tenant access denial. - Encrypt tenant secrets such as bot tokens, provider keys, and webhook secrets. Recommended stronger mode: - Per-tenant database user or schema for commerce data. - Platform-owned accounting database remains separate. - Scanner receives only payment-watch instructions and returns normalized evidence. - Accounting bridge reads only aggregated billing events, not arbitrary tenant content. ## Platform connections that cross isolation Some platform services must intentionally cross tenant boundaries. These should be explicit, audited, and narrow. ### Scanner connection The scanner should not need broad access to tenant storefront data. It should receive: - Payment id or platform reference. - Tenant id. - Chain id. - Token address. - Destination address. - Expected amount and decimals. - Expiry and watch mode. - Webhook callback target. It should return: - Balance or transaction evidence. - Chain, token, address, amount, tx hash where available. - Confidence and status. - Raw evidence fingerprint. The backend then decides whether that evidence funds escrow, marks a direct payment paid, or stays pending. ### Accounting and billing connection Amanat needs enough cross-tenant data to bill merchants. Billing should consume normalized events: - Tenant activated. - Domain active. - Bot active. - Order created. - Payment paid. - Escrow funded. - Escrow released. - Refund processed. - External payment recorded. - Scanner watch created or consumed. - Support/dispute intervention used. Billing does not need raw buyer messages, full product descriptions, or tenant secrets. ### Operator support and abuse connection Amanat operators need limited break-glass access for: - Fraud and abuse investigation. - Payment disputes. - Legal or compliance requests. - Tenant suspension. - Bot/domain disablement. Every break-glass read should be logged with actor, reason, tenant, object id, and timestamp. ## Proposed data objects ### Tenant ```ts interface Tenant { id: string; ownerUserId: string; type: "hosted_seller" | "white_label" | "isolated" | "enterprise"; status: "pending" | "active" | "suspended" | "closed"; displayName: string; billingAccountId?: string; isolationMode: "shared" | "schema" | "database" | "stack"; createdAt: string; updatedAt: string; } ``` ### TenantDomain ```ts interface TenantDomain { id: string; tenantId: string; hostname: string; mode: "managed_ns" | "cname"; status: "pending" | "active" | "degraded" | "suspended" | "removed"; verificationToken: string; tlsStatus: "pending" | "issued" | "failed" | "expired"; lastCheckedAt?: string; } ``` ### TenantBot ```ts interface TenantBot { id: string; tenantId: string; telegramBotId: string; username: string; encryptedTokenRef: string; webhookSecretRef: string; status: "pending" | "active" | "suspended" | "revoked"; miniAppUrl?: string; lastWebhookAt?: string; } ``` ### TenantIntegration ```ts interface TenantIntegration { id: string; tenantId: string; kind: "catalog" | "delivery" | "payment" | "accounting" | "notification"; provider: string; status: "draft" | "active" | "error" | "disabled"; configRef: string; lastSyncAt?: string; lastError?: string; } ``` ### TenantPaymentPolicy ```ts interface TenantPaymentPolicy { id: string; tenantId: string; allowedRails: Array<"amn_escrow" | "amn_direct" | "external_provider" | "manual_invoice">; defaultRail: "amn_escrow" | "amn_direct" | "external_provider" | "manual_invoice"; escrowRequiredAboveAmount?: string; escrowRequiredForCategories?: string[]; buyerDisclosureMode: "plain" | "strict"; } ``` ## Authentication and authorization Tenant users are not only platform users. They also need tenant-scoped roles. Suggested roles: | Tenant role | Capabilities | | --- | --- | | Owner | Full tenant admin, billing, domain, bot, integrations, payment policy | | Manager | Catalog, orders, delivery, support | | Finance | Payments, payouts, invoices, reports | | Support | Buyer messages, order updates, dispute evidence | | Developer | Webhooks, API keys, integration logs | Platform `admin` remains separate from tenant roles. A platform admin can administer tenants through operator tooling, but tenant users should not become platform admins. ## API direction Tenant-aware API surfaces should make tenant context explicit. Examples: ```text GET /api/tenants/:tenantId/bootstrap POST /api/tenants/:tenantId/domains POST /api/tenants/:tenantId/telegram/bot GET /api/tenants/:tenantId/catalog/products POST /api/tenants/:tenantId/orders POST /api/tenants/:tenantId/payments/intents POST /api/tenants/:tenantId/integrations/:integrationId/webhook ``` For public storefront calls, the backend can resolve tenant from host and expose shorter paths: ```text GET /api/storefront/bootstrap GET /api/storefront/catalog POST /api/storefront/checkout GET /api/storefront/orders/:orderId ``` The resolved tenant id must be server-side, not trusted from a browser-supplied header. ## Order lifecycle White-label orders can map to Amanat purchase requests where escrow or negotiation is needed. Simpler direct purchases may use a lighter order model that still links to payment and delivery evidence. ```mermaid stateDiagram-v2 [*] --> draft draft --> pending_payment : checkout submitted pending_payment --> paid_direct : amn_direct or external provider confirms pending_payment --> escrow_funded : amn_escrow confirms paid_direct --> fulfillment escrow_funded --> fulfillment fulfillment --> delivered delivered --> completed delivered --> disputed : buyer or seller opens issue escrow_funded --> disputed : issue before delivery disputed --> completed : release or refund resolved pending_payment --> expired draft --> cancelled ``` The UI must label the protection mode clearly: - **Protected by Amanat escrow** when `amn_escrow` is active. - **Paid through Amanat, no escrow hold** when `amn_direct` is active. - **Paid outside Amanat** when external payment evidence is recorded but Amanat is not the payment custodian. ## Admin experience ### Merchant admin Merchant admins need: - Shop branding. - Domain setup. - Telegram bot setup. - Catalog source setup. - Delivery setup. - Payment policy and allowed rails. - Orders and buyer support. - Payouts and settlement reports. - Billing invoices from Amanat. - Integration logs and webhook delivery status. ### Amanat operator admin Platform operators need: - Tenant approval and suspension. - Domain and TLS health. - Bot token validation and revocation. - Payment rail enablement. - Scanner watch health by tenant. - Billing event stream. - Abuse and dispute dashboards. - Break-glass audit logs. ## Security requirements - Encrypt all tenant-provided secrets at rest. - Never expose Telegram bot tokens or provider keys to frontend code. - Verify Telegram webhook secrets per tenant bot. - Verify integration webhooks with tenant-specific secrets. - Rate-limit public storefront and bot endpoints by tenant, IP, user, and action. - Enforce tenant scoping at service and query layers. - Add cross-tenant regression tests for every tenant-owned resource. - Log operator break-glass access. - Support emergency tenant suspension that disables domains, bot webhooks, checkout, and external webhooks. - Use strict buyer disclosures when checkout is not escrow-protected. ## Billing model Possible merchant billing levers: - Monthly tenant subscription. - Domain or bot add-on fee. - Percentage of GMV through Amanat escrow. - Lower percentage or flat fee for Amanat direct payments. - Scanner usage fee for balance watches or confirmations. - Support or dispute intervention fee. - External integration add-on fee. Billing events should be generated from canonical domain events, not from frontend analytics. ## Rollout phases ### Phase 0 - Design and model alignment - Define `Tenant`, `TenantDomain`, `TenantBot`, and `TenantIntegration` models. - Decide first isolation level. - Define tenant auth claims and tenant roles. - Extend payment rail taxonomy with `amn_escrow`, `amn_direct`, and `external_provider`. - Decide whether first release maps all tenant orders to `PurchaseRequest` or introduces a lighter `Order` model. ### Phase 1 - Hosted seller storefront - Support `seller.amn.gg` tenant storefronts. - Reuse existing shop settings and request templates. - Add tenant bootstrap endpoint. - Add tenant-aware frontend theming. - Keep data in shared DB with strict `tenantId` scoping. ### Phase 2 - Custom domain and white-label frontend - Add domain validation. - Add TLS provisioning. - Resolve tenant by host. - Add tenant branding and no-label mode. - Add operator admin for domain state. ### Phase 3 - Tenant Telegram bot - Store encrypted bot token. - Register tenant webhook. - Route Telegram updates by bot. - Add tenant Mini App launch and startapp context. - Reuse Telegram auth retry rules from [[RTK]] and existing Telegram Mini App flow. ### Phase 4 - Payment policy and direct Amanat rail - Add tenant payment policy. - Support Amanat escrow and Amanat direct side by side. - Use scanner evidence for direct payments where possible. - Add clear buyer disclosure and order-state differences. ### Phase 5 - Integrations and stronger isolation - Add generic catalog endpoint adapter. - Add delivery webhook adapter. - Add external payment provider adapter. - Offer tenant schema/user or dedicated database for higher tiers. - Add billing event stream and invoices. ## Open questions - Should a merchant tenant always be backed by an Amanat seller user, or should tenant ownership be a separate organization model? - Do white-label buyers need Amanat accounts, tenant-local accounts, Telegram-only identity, or guest checkout? - Should direct Amanat payment route funds to a merchant wallet, a platform collection wallet, or per-tenant derived addresses? - How much Amanat branding is legally required when escrow is active? - Can tenants bring their own payment provider if Amanat is still shown as escrow operator? - Should tenant stores use the same dispute process as the marketplace, or a merchant-specific support ladder first? - What is the minimum isolation level acceptable before custom domains and custom bots are allowed? - Should Telegram bot ownership be verified through BotFather token validation alone, or also through a tenant admin challenge? - Should the first implementation prioritize Telegram shops before web shops, given the existing Telegram roadmap? ## Decision sketch The safest first product path is: 1. Start with approved merchant tenants only. 2. Launch hosted subdomain shops before custom domains. 3. Keep one frontend codebase and add tenant bootstrap/theming. 4. Add `tenantId` scoping first, with repository tests for isolation. 5. Add tenant Telegram bots after host-based tenant resolution exists. 6. Keep Amanat escrow as the default payment rail. 7. Add `amn_direct` only with explicit buyer disclosure and scanner-backed evidence. 8. Use accounting events for billing, not direct access to tenant content. This gives sellers the feeling of owning their shop and bot while keeping Amanat's platform controls intact.