23 KiB
title, tags, created, status
| title | tags | created | status | |||||||
|---|---|---|---|---|---|---|---|---|---|---|
| PRD - Seller-Owned White-Label Shops and Bots |
|
2026-06-06 | 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.comto 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:
- Request host, such as
shop.example.com. - Amanat subdomain, such as
seller.amn.gg. - Explicit tenant slug for preview and fallback URLs, such as
amn.gg/t/{tenantSlug}.
The frontend loads a tenant bootstrap payload:
{
"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:
POST /api/telegram/tenant/:tenantId/webhook/:secret
or bot-specific:
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:
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.
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
tenantIdto 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
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
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
interface TenantBot {
id: string;
tenantId: string;
telegramBotId: string;
username: string;
encryptedTokenRef: string;
webhookSecretRef: string;
status: "pending" | "active" | "suspended" | "revoked";
miniAppUrl?: string;
lastWebhookAt?: string;
}
TenantIntegration
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
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:
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:
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.
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_escrowis active. - Paid through Amanat, no escrow hold when
amn_directis 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, andTenantIntegrationmodels. - Decide first isolation level.
- Define tenant auth claims and tenant roles.
- Extend payment rail taxonomy with
amn_escrow,amn_direct, andexternal_provider. - Decide whether first release maps all tenant orders to
PurchaseRequestor introduces a lighterOrdermodel.
Phase 1 - Hosted seller storefront
- Support
seller.amn.ggtenant storefronts. - Reuse existing shop settings and request templates.
- Add tenant bootstrap endpoint.
- Add tenant-aware frontend theming.
- Keep data in shared DB with strict
tenantIdscoping.
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:
- Start with approved merchant tenants only.
- Launch hosted subdomain shops before custom domains.
- Keep one frontend codebase and add tenant bootstrap/theming.
- Add
tenantIdscoping first, with repository tests for isolation. - Add tenant Telegram bots after host-based tenant resolution exists.
- Keep Amanat escrow as the default payment rail.
- Add
amn_directonly with explicit buyer disclosure and scanner-backed evidence. - 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.