# Environments, authentication, and roles Every credential belongs to one environment, one partner tenant, and one narrow role. The API uses HTTPS Bearer authentication from confidential server workloads only. Tenant identity is derived from the credential, never from a caller-supplied header or request field. Catalog data, approved disclosures, policy links, webhook registration, return configuration, and co-brand copy are bound to that same tenant. The catalog's `partner_id` is an opaque tenant key. It is 2–32 characters and matches `^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$` (for example, `example-partner`); compare it exactly and never convert it into a hostname, database/table name, secret path, or authorization decision. ## Environment map | Resource | Sandbox | Production | |---|---|---| | JSON API | exact working `CHIA_API_ORIGIN` from signed sandbox onboarding | separate exact working `CHIA_API_ORIGIN` from signed production onboarding | | authenticated assets | exact `CHIA_ASSET_ORIGIN` from sandbox onboarding | exact production asset origin from signed onboarding | | care origin | exact sandbox value | exact production Chia origin | | runtime key prefix | `chia_test_…` | `chia_live_…` | | finance key prefix | `chia_test_finance_…` | `chia_live_finance_…` | | webhook secret prefix | `whsec_test_…` | `whsec_live_…` | | data | synthetic only; never charges or creates a patient | pre-activation catalog/handoff fail closed; after written activation, approved live catalog and Chia-hosted purchase flow; no patient data returned to the partner | API and care origins are not inferred from one another. Pass all exact origins from signed onboarding to the SDK in both environments; it rejects API responses and handoff/neutral URLs for any other origin. The `.invalid` origins in machine contracts are deliberately non-resolving placeholders, not executable defaults. Begin the integration clock only when Chia supplies working exact origins, health evidence, and credentials in signed onboarding. The credential sets have deliberately different authority: - sandbox credentials allow synthetic catalog, consented handoff creation, settlement fixtures, and all three synthetic webhook shapes; - production runtime credentials always allow authentication and all three synthetic webhook shapes; live catalog and consented co-branded handoff creation remain fail-closed until written production activation; - production finance credentials allow only the settlement operation; production 2.1 returns only append-only immutable statement revisions explicitly authored and released by Finance. Never use a sandbox key/secret at the production origin or a production key/secret at the sandbox origin, even for diagnostics. ## Least-privilege roles | Role | Secret | Allowed | Explicitly refused | |---|---|---|---| | runtime catalog/handoff service; ephemeral test job | runtime key | `catalog:read`, `handoffs:create`, authenticated asset GET, `webhooks:test` | settlements, webhook verification | | webhook receiver | current signing secret; optionally one retiring secret | verify inbound Chia events | every Partner API call | | finance worker | finance key | `settlements:read` | catalog, assets, webhook tests | | mobile app | none | partner-projected cards and OS-browser navigation | all Chia API/asset/SDK access | Use the role-narrowed factories. TypeScript removes finance methods from a runtime client and runtime methods from a finance client, while the SDK also rejects wrong environment/key combinations at runtime. ```ts import { createFinancePartnerClient, createRuntimePartnerClient, } from "@chiahealth/partner"; const runtime = createRuntimePartnerClient({ environment: "sandbox", apiOrigin: process.env.CHIA_API_ORIGIN!, assetOrigin: process.env.CHIA_ASSET_ORIGIN!, runtimeKey: process.env.CHIA_RUNTIME_KEY!, careOrigin: process.env.CHIA_CARE_ORIGIN!, }); const finance = createFinancePartnerClient({ environment: "sandbox", apiOrigin: process.env.CHIA_API_ORIGIN!, financeKey: process.env.CHIA_FINANCE_KEY!, }); ``` Do not put runtime, finance, or webhook-signing secrets in the same process merely because the example is short. The webhook-test command is the sole exception to one operation per process: it is an ephemeral job in the runtime credential domain, not a fourth credential. ## Secret handling - Chia provisions six environment- and role-isolated values: sandbox runtime, sandbox finance, sandbox webhook, production runtime, production finance, and production webhook credentials. - Deliver raw values through the mutually approved authenticated secret channel directly into named secret-manager destinations. - Never send them in the release manifest, email, chat, tickets, CI artifacts, logs, source control, `.env` commits, mobile remote config, or browser bundles. - Treat the visible prefix as non-secret only for routing/debugging; do not log a complete value or use prefix text as authorization. - Restrict each persistent workload's identity/IAM policy to only its secret. Inject the runtime key into the one-shot test job only for its execution. Startup refusal is defense in depth, not a substitute for deployment isolation. - Revoke and audit runtime, finance, and webhook credentials independently. ## Environment isolation A sandbox credential fails on production and a production credential fails on sandbox. Also isolate: - receiver hostname/path and TLS ownership; - deployment identity, secret store, database/queue, metrics, and alerts; - idempotency and webhook-deduplication stores; - API origin and activation state; - care origin, return allowlist, cookies/sessions, and mobile association files. Never copy sandbox payloads, synthetic settlement rows, event IDs, or caches into production. Production settlement rows are finance-only business releases and must never enter the runtime, mobile, webhook, or general analytics boundary. Production synthetic webhook tests are real production deliveries marked `livemode: true` and `test: true`; the test flag still requires the first no-side-effect branch. ## Rotation For API keys, provision and validate the replacement in the exact environment/role, switch the workload, then revoke the old key through the Chia control process. Do not overlap keys across roles. For webhook secrets: 1. Install the new secret in the receiver while retaining the old active secret. 2. Accept the single received `v1` signature when it validates against either secret for a short, agreed overlap. 3. Have Chia switch its sender to the new secret; each request still contains exactly one signature. Observe successful signed tests. 4. Remove the old retiring secret. The current and retiring values must be distinct. Never accept more than two signing secrets or mix `whsec_test_` and `whsec_live_` in one receiver.