> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackra.figentra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 0376 — Provider resolution ports, credential references, managed or own accounts, and the telephony ports

> Proposed · 2026-10-26

> [!NOTE]
>
> Proposed (STA-806). It names the ports through which
> [0356](https://docs.stackra.figentra.com/adr/0356-choosing-a-provider-per-tenant-and-market-through-the-connection-with-a-market-default.md)
> (a provider per tenant and Market) is carried out, and settles that ADR's open question 1. It
> reads with
> [0308](https://docs.stackra.figentra.com/adr/0308-integrations-v3-1-provider-descriptions-connection-stores-and-webhooks.md)
> (connections),
> [0355](https://docs.stackra.figentra.com/adr/0355-marketplace-one-integration-with-up-to-five-roles-one-app-market-and-open-to-any-developer.md)
> (one Integration per provider) and
> [0370](https://docs.stackra.figentra.com/adr/0370-market-packs-signed-dated-overlaid-data-with-pins-and-legal-floors.md) (market
> packs). It answers the wave 10 notifications builder's questions 1, 2 and 9 and the payments
> builder's question 7.

> [!NOTE]
>
> Amended 2026-10-26 (STA-1282, capability map M2, owner decision R3-1): decision 1's list gains
> **verification** (KYC and KYB, pack key `providers.verification`). Figentra's own checks of a
> tenant are pinned to platform Connections (`ProviderResolver#candidates(..., { pin: "managed" })`),
> so a tenant's own account never answers them; a tenant's checks of its own customers resolve the
> tenant's own Connection first, then the managed one. `@stackra/identity` keeps the `Verification`
> port and runs the list in `VerificationService#verifyThrough`.

## Context

Wave 10 built, in `@stackra/integrations`, a `ProviderResolver` service over three dependencies (the `ConnectionStore`,
a `ProviderDefaults` port and a `MarketContext` port), a `CredentialRef` type `<provider>:conn_<id>`, and a
`VoiceGateway` interface for telephony. It left open which Market keys a non-payment capability, who binds the two
ports, and how a tenant gets a provider Figentra runs for it. Since then the owner set the principle "managed or bring
your own" for every provider category (2026-10-26), review round 2 named the records the ports read (X2-1, X2-18),
round 3 named the managed half (R3-SO-03), the overlay subject (R3-SO-01) and the voice split (R3-SO-11), and X2-30
found that a licensed Saudi carrier offers a SIP trunk, not conversational steps.

## Decision

1. **`ProviderResolver` is the one choice rule.** Every capability with several providers (SMS, WhatsApp, voice,
   speech, mail, geocoding, accounting, tax, terminals, shipping) resolves the Connection for a call through
   `ProviderResolver`: the tenant's own Connection of a provider the Market offers wins; otherwise the Market's
   platform Connection serves; a stored record reloads the exact Connection that served it. Payments keep their
   own `PaymentGateways` resolver on the same rule. `@Replaces` is never used for this (0356 decision 1).
2. **`ProviderDefaults` reads two records.** Its driver reads `market-pack:<code>.providers` for what depends on the
   market (payments, sign-in, messaging, tax, terminals, telephony) and `region-map:<region>.providers` for what
   depends on where the tenant's data lives (mail, AI, speech, storage), and returns the providers in order with the
   platform Connection of each (X2-1). A tenant changes its provider through its own Connection, never by editing a
   pack.
3. **`MarketContext` resolves by subject.** Each pack key declares the subject it applies to: `location`, `buyer`,
   `entity` or `tenant` (R3-SO-01). `MarketContext` answers the Market of a call (`market()`, as built) and gains
   `packFor(record, subject)` for record rules. The seeded subjects for providers are: SMS, WhatsApp and voice by the
   recipient (`buyer`), because sender-ID, consent and quiet-hours rules are the destination's law; mail, accounting
   and fiscal by the legal entity (`entity`); payments by the checkout's Market (0244); a shared process (a data
   subject request clock, retention, a breach notice) takes the strictest active pack (RV-4, X2-18). The subject of
   a key is pack data; the driver lives in the OS tenancy service.
4. **Who binds the ports.** `@stackra/market-packs` verifies and resolves packs; the OS tenancy and markets service
   fetches pack versions (through `@stackra/assets` content hashes), and binds `ProviderDefaults`, `MarketContext` and
   the other pack readers (`MarketPaymentDefaults`, `FiscalPackSource`, settings floor sources) over it. No Stackra
   package fetches a pack.
5. **Managed or bring your own.** A Connection is one of two modes: **managed** (Figentra's account and key, plus a
   per-tenant resource on it: a messaging subaccount and its registrations, a connected payments account, a sending
   domain, a WhatsApp number, a tax company) or **own** (the tenant's own account and key). An Integration that
   offers the managed mode implements `ManagedProvisioning` (create, verify, suspend and remove the per-tenant
   resource, report its status and its cost events), run by `workflow-template:os:managed-provisioning:<category>`.
   Which modes a category offers per pack, and the fee of each, are `provider-category:<category>` and rate-card
   records (R3-SO-03). The Connection carries `mode: live | test`; the tenant kind sets it (X2-24).
6. **Credential references.** A record that must remember an account stores a `CredentialRef`,
   `<provider>:conn_<id>`, never a secret. `ProviderResolver#byRef` loads that Connection through the store, which
   applies the caller's scope and decrypts. A reference whose Connection is gone or out of scope refuses; it never
   falls back to another Connection. A reference is classified `internal`; the Connection's secrets stay in the
   integrations vault.
7. **Telephony is two ports.** `VoiceGateway` (in `@stackra/integrations/contracts`) places, steers, records and ends
   calls over a provider (Twilio) or a SIP driver for a carrier that only gives a trunk. `Speech` (streaming
   speech-to-text and text-to-speech) is a separate port; language and dialect come from pack data, the provider from
   `region-map:<region>.providers.speech` (in-region and without retention for the health and privileged classes),
   and a device-audio driver serves drive-through and till microphones. The voice provider per pack is pack data
   (X2-30). Calls and speech are metered as `voice.minutes` and `speech.seconds` (R3-SO-11).
8. **One Meta Integration.** WhatsApp, ads, catalogue and tracking are roles of one Meta Integration in
   `@stackra/integrations` (0355 decision 5); `notifications` uses its WhatsApp role.
9. **Values.** Pack data: `providers.*` per market, each key's subject, telephony and speech providers, recording
   notice floors. Seed data: `region-map` providers, `provider-category` records, rate cards, managed-provisioning
   workflow templates. Settings: none. Rule sets: message channel order and fallback (`rule-set:os:message-fallback`).
   Deployment data: platform Connection ids.

## Consequences

* A provider change for a market is a pack edit; a tenant's own provider is an app-market install.
* Every call can say which Connection served it, which reconciliation and audit need.
* The SIP driver and the `Speech` port are new build items; the speech-through-voice-provider shortcut of wave 10
  goes away.

## Enforcement

planned — `@stackra/integrations` tests: resolution order, `byRef` refusing a missing Connection, and no fallback for a
stored record; the market-pack section schema refuses a `providers` key without a subject.

## Supersedes and sources

Supersedes: none. Settles 0356 open question 1. Sources: `notes/handover/build-wave10-2026-10-25.md` (notifications
builder, questions 1, 2 and 9; payments builder, question 7); `notes/handover/cross-product-answers.md` (managed or
bring your own); `notes/handover/review-round-2/cross.md` (X2-1, X2-18, X2-24, X2-30);
`notes/handover/review-round-3/stackra-os.md` (R3-SO-01, R3-SO-03, R3-SO-11, R3-SO-19).

## Amendment 2026-10-26: decisions 5 and 8, vendor code in OS integrations (STA-1280, [0443](https://docs.stackra.figentra.com/adr/0443-integration-architecture-connectors-apps-and-extensions-in-one-marketplace-and-vendor-drivers-in-os-integrations))

* **Decision 5.** The `ManagedProvisioning` port, the Connection modes and the provisioning workflow contracts stay in
  `@stackra/integrations`. Each vendor's implementation of `ManagedProvisioning` lives with that vendor's Integration
  in the OS integrations service (owner R3-8). A `managed` Connection may also point at a self-hosted open-source
  default that Figentra runs on the regional tools stack (Documenso, PaddleOCR or Surya, Nominatim and Photon,
  LibreTranslate, Chatwoot; owner R3-5); it resolves through `ProviderResolver` like any other Connection.
* **Decision 8.** The one Meta Integration is an OS integrations class, not a class in `@stackra/integrations`; the
  rule of one Integration with several roles stands.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.