One-hour integration
At the end of this guide you will have fetched and safely cached the sandbox catalog, created and opened a consent-gated short-lived handoff, verified all three signed webhook shapes, and read a synthetic settlement page. No Chia credential will enter the mobile app.
The clock starts after Chia delivers the complete onboarding package, all sandbox origins resolve, and the partner has a public HTTPS webhook endpoint. It does not include Chia deployment, credential delivery, legal review, certification, or live activation.
Before you start#
You need Bun 1.3.11 to run the bundled reference (the SDK supports Node.js 20.11+), plus curl, jq, cosign, a secret manager, three persistent secret domains, and one ephemeral test job:
| Workload | Allowed secret |
|---|---|
| runtime catalog service | CHIA_RUNTIME_KEY |
| one-shot webhook-test job in the runtime domain | CHIA_RUNTIME_KEY |
| webhook receiver | CHIA_WEBHOOK_SECRET_CURRENT and optionally one retiring secret |
| finance worker | CHIA_FINANCE_KEY |
Every API process also gets the non-secret exact CHIA_API_ORIGIN from onboarding and CHIA_ENVIRONMENT=sandbox. The catalog service gets exact CHIA_ASSET_ORIGIN and CHIA_CARE_ORIGIN too. Reserved API names are contract targets, not availability claims; static .invalid asset/care values are intentionally unusable fixtures. The test job is not a fourth credential domain: it receives the same runtime key only for the duration of the command and then exits.
0–10 minutes: verify and install#
Run the complete keyless manifest and archive verification block in Onboarding. Then extract the integration archive, enter its single top-level directory, and verify its closed file allowlist and machine entry points:
python3 scripts/partner_contracts/verify_integration_bundle.py .
python3 scripts/partner_contracts/check_compatibility.py \
--validate-all --output json
python3 scripts/partner_contracts/check_renderer_conformance.py
From your backend project, install the exact verified tarball by filesystem path:
npm install --save-exact --ignore-scripts --no-audit --no-fund \
/verified/chia-bundle/sdk/chiahealth-partner-2.1.0.tgz
Do not substitute a registry package or unverified archive. Store the sandbox runtime, webhook, and finance secrets directly in their separate workload scopes.
Checkpoint: the three persistent domains start with only their allowed secret; the one-shot test job accepts only the runtime key and persists no credential.
10–25 minutes: fetch and cache the catalog#
The fastest runnable path is the included reference service:
cd examples/partner-reference-backend
bun install --frozen-lockfile --ignore-scripts
cp .env.serve.example .env.serve
# Fill only CHIA_ENVIRONMENT, CHIA_API_ORIGIN, CHIA_ASSET_ORIGIN, CHIA_RUNTIME_KEY, and CHIA_CARE_ORIGIN.
env -i PATH="$PATH" sh -c 'set -a; . ./.env.serve; set +a; bun run start'
It immediately fetches the catalog, streams and verifies each authenticated image, atomically swaps the complete publication, then refreshes conditionally on a backend schedule. It never calls Chia because a user viewed a card.
Verify the mobile-safe projection with fresh synthetic local state evidence:
curl --fail-with-body --silent --show-error \
-H 'X-Demo-Service-State: CA' \
-H "X-Demo-State-Observed-At: $(date -u +%Y-%m-%dT%H:%M:%SZ)" \
http://localhost:8787/catalog | jq
For direct API smoke tests from the bundle root:
bash partner-docs/curl-quickstart.sh runtime
Inject CHIA_ENVIRONMENT=sandbox and CHIA_RUNTIME_KEY into this process from the isolated runtime secret scope before running the command; never paste the value into shell history or give it to a coding agent. Run the credentialed job inside the partner's workload and return only its fixed status output to the agent. This direct curl check performs only the safe catalog read and discards its body so authenticated asset URLs and handoff fragments do not enter terminal or agent logs. Use the durable reference sender below for webhook tests; a throwaway curl UUID would violate the idempotency contract on an uncertain network outcome.
Your production implementation must preserve the last complete valid, unexpired publication while a retryable refresh fails. Never partially publish a new catalog, serve unverified bytes, or retain a publication past its expiry.
Checkpoint: /catalog contains no Chia asset URL or credential, required fields are complete, and each image path is random and partner-owned.
Open http://localhost:8787/demo for the complete sandbox renderer. Its page, styles, state handling, closed backend projection, and conformance fixtures are included in the signed bundle. Production implementations replace the demo state headers with authenticated account state but preserve the renderer and action contract.
25–35 minutes: implement the handoff#
Use resolveCatalogHandoff with fresh, authenticated partner account service-state evidence. The resolver returns exactly one of:
hidden: render nothing;neutral_only: render oneContinue to Chiaaction;share_or_neutral: render the full JIT disclosure and both equal-access actions.
At the user's tap, resolve the evidence again. For neutral_only or the no-share action, pass the neutral URL directly to the platform OS-browser API. For affirmative share consent, send only catalogItemId, disclosureVersion, and the consent timestamp to your backend; the backend calls runtime.createHandoffSession with a persisted random UUIDv4 idempotency key. It returns only the resulting URL and expiry to that one mobile response. Open promptly using the appropriate iOS, Android, React Native, or Flutter snippet. Never send a partner user/account/device/contact identifier, persist/log the URL, or call a nonexistent status endpoint.
const handoff = await runtime.createHandoffSession({
catalogItemId: item.id,
disclosureVersion: item.handoff.version,
consentAttestation: { affirmed: true, affirmedAt: new Date().toISOString() },
idempotencyKey: await operationStore.getOrCreateRandomUuidV4(operationId),
});
return { url: handoff.data.url, expiresAt: handoff.data.expires_at };
Checkpoint: share and no-share open in the system browser; the share URL expires after 15 minutes and contains no test or identity field; missing/stale evidence hides or degrades to neutral exactly as the resolver specifies; app focus/return never becomes a conversion signal.
35–50 minutes: receive and test webhooks#
Start the separately scoped receiver:
cd examples/partner-reference-backend
cp .env.receiver.example .env.receiver
# Fill only the environment and webhook signing secret(s).
env -i PATH="$PATH" sh -c 'set -a; . ./.env.receiver; set +a; bun run webhook-receiver'
Expose /webhooks/chia through the exact registered HTTPS URL. The reference implementation preserves the raw body, verifies timestamp/signature/header/envelope/environment, requires test: true, deduplicates by event ID, and commits only a no-side-effect receipt. V2 has no live business handler.
Request all three shapes from an ephemeral runtime-only process. This is process isolation for a one-shot operation, not a separate API credential:
cd examples/partner-reference-backend
cp .env.webhook-test.example .env.webhook-test
env -i PATH="$PATH" sh -c 'set -a; . ./.env.webhook-test; set +a; bun run test-webhooks'
Run it twice. The second set has new event IDs; separately replay one captured signed request in your test harness to prove the same event ID is handled once. All three synthetic shapes in both environments must return success with zero cache, finance, accounting, care, notification, or analytics side effects.
Checkpoint: endpoint.test, catalog.updated, and settlement_summary.finalized are observed; duplicates are harmless; no signed value is copied into a downstream job.
50–55 minutes: read settlement summaries#
Run the isolated finance worker:
cd examples/partner-reference-backend
cp .env.finance.example .env.finance
env -i PATH="$PATH" sh -c 'set -a; . ./.env.finance; set +a; bun run finance'
Or from the bundle root:
bash partner-docs/curl-quickstart.sh finance
Inject CHIA_ENVIRONMENT=sandbox and CHIA_FINANCE_KEY from the isolated finance secret scope before running it. The smoke script discards the settlement body; inspect persisted summaries only inside the finance boundary.
These sandbox rows are synthetic, including all amounts and activity. See Settlement summaries.
Checkpoint: finance cannot fetch catalog/assets and catalog cannot fetch settlements.
55–60 minutes: production connectivity certification#
Deploy the same three-role topology with wholly separate production values: chia_live_… runtime, chia_live_finance_… finance, and whsec_live_… receiver secret. Never copy sandbox state, credentials, idempotency records, or webhook receipts.
- Authenticate with the production runtime key. Before activation, confirm
catalog and handoff fail closed with production_catalog_not_approved; credentials alone are not commerce authorization.
- Request all three synthetic webhook shapes. Prove every received event has
livemode:true, test:true, and no business side effect.
- Read the production summary list with the isolated finance key. Accept only
closed immutable release rows, persist each id once, and apply supersedes_id before computing an effective view. An empty page does not prove zero activity, liability, payment, or amount owed.
- Confirm no credential appears in mobile, logs, support tooling, or
analytics and no patient/order/shipment status returns to the partner.
The technical integration can now be complete without a commercial agreement or live purchase. After the signed activation receipt exists, re-fetch the approved production catalog, create the identity-free handoff, open it in the OS browser, confirm the <Partner> × Chia experience and tracker suppression, and complete the separately authorized end-to-end purchase acceptance test.
If anything fails, use Troubleshooting and escalate with a validated Chia-Request-Id when present, never a payload or secret.