Skip to main content
Run this the day you flip from the sandbox to production. It is a short, mechanical pre-flight — eight checks, each with a copy-paste command and a link to the page that owns the detail. Nothing here is aspirational: every command below was run live against the sandbox census.
This is the engineering pre-flight — not accreditation. Getting your entry onto the production Trust List is a separate governance gate with its own vetting, SLA, and eligibility bar. Do that on Production Accreditation. Come back here for the code-side switch-over once you are cleared.

The checklist

  • 1. Rotate test → live keys — mint phosra_live_ keys; retire every phosra_test_ key from prod config
  • 2. Lock scopes to least privilege — each key holds only the scopes its service calls
  • 3. Verify webhook signatures in prod — reject any delivery whose HMAC does not recompute
  • 4. Arm Deprecation / Sunset monitoring — alert on any Deprecation or Sunset response header
  • 5. Diff sandbox → prod config — base URL, trust root, and org id all move together
  • 6. Confirm rate-limit headroom — read X-RateLimit-Remaining; back off on 429, never hammer
  • 7. Pin exact SDK versions — no caret ranges on a pre-1.0 line
  • 8. Wire health / status monitoring — poll /health and the trust-list ETag
1

Rotate test → live keys

A phosra_test_ key only works against the sandbox base URL; a phosra_live_ key only works against production. Mint live keys, load them into your prod secret manager, and make sure no phosra_test_ value survives in production config.
Mint a live key
The raw key is in the response key field and is shown exactly once — only a SHA-256 hash is stored. Prefer zero-downtime rotation (mint the new key, deploy, then revoke the old) so nothing breaks mid-cutover.Authentication · test vs live keys
2

Lock scopes to least privilege

Every key carries an explicit scope list; a call to a route your key lacks returns 403, never silent success. Grant the fewest scopes each service needs — a read-only reporting job should never hold write:enforcement. If one key leaks, the blast radius is only that key’s scopes on that one environment.
Read the scopes bound to a key
Authentication · scoping
3

Verify webhook signatures in prod

Every delivery is signed t=<unix>,v1=<hex> in the X-Phosra-Signature header. Recompute HMAC-SHA256(secret, "<t>." + rawBody) over the raw body and reject on any mismatch — otherwise anyone who learns your endpoint URL can forge policy-change events. Use the per-environment signing secret returned when you register the production webhook, and compare in constant time.
Recompute and compare (bash)
Webhooks · verifying signatures (copy-paste verifiers in TypeScript, Python, and Go)
4

Arm Deprecation / Sunset monitoring

Before any v1 endpoint or field changes, the census sends RFC 9745 Deprecation and RFC 8594 Sunset response headers through the entire advance-notice window. Log or alert on their presence so a migration deadline never reaches you as a surprise 410. Today the sandbox sends none — a clean scan is the healthy baseline you are monitoring for change against.
Scan for lifecycle headers (empty today = healthy)
Deprecation & Sunset Policy · on the wire
5

Diff sandbox → prod config

Three values change together when you leave the sandbox. Miss one and a phosra_live_ key will hit the sandbox census (or vice-versa) and fail closed.Do not copy the sandbox trust root into production — the production census root is a different Ed25519 identity (root-prod-bootstrap-2026-07 on the interim production census), and pinning the wrong one makes every signature verification fail. The trust-root X is an out-of-band pin: you receive it at accreditation and hard-code it. Before you pin, confirm the census you are about to trust actually verifies under the root X you were handed out-of-band. Check the signature, not just the key_id: the id is a label and labels collide (both Phosra sandbox censuses publish root-sandbox-2026-06 over different key material). Never adopt a root just because a census served it:
Confirm the production census root (run live)
Output
Then verify the detached signature over the document string against your pinned root X (824vsCATBxyUiA-znpGx01N48NNs_3gPE3M7f7vIEaI) with your Ed25519 library of choice — a matching key_id alone proves nothing. If the curl fails with SSL: no alternative certificate subject name matches target host name, that is a known intermittent Railway edge certificate issue on prodapi.phosra.com: retry, or use the equivalent https://phosra-api-prod-bootstrap-production.up.railway.app (same census, same root).Once the capabilities self-cert ships, you can confirm a candidate census cryptographically: fetch GET /.well-known/ocss/capabilities, verify its root signature against your pinned root X, and read back environment: "production" and root_key_id: "root-prod-bootstrap-2026-07" — a self-certifying check that never sources the root from the census.For an end-to-end round-trip, phosra doctor drives all three values at once. It reads the census from the environment (there is no --env flag) — override PHOSRA_CENSUS_URL and PHOSRA_TRUST_ROOT_X to point it at any census without touching your config file:
Drive the doctor against a chosen census
CLI · phosra doctor · Production Accreditation · after you are accredited
6

Confirm rate-limit headroom

Every metered response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (unix epoch seconds). Read them instead of hard-coding a quota, and on a 429 sleep until the reset — never retry immediately. Check your standing before a launch that spikes traffic:
Read your current window
Response headers
Rate limits · read your window
7

Pin exact SDK versions

The published SDKs are pre-1.0, so a 0.x minor bump may carry breaking changes. Pin the exact version you tested against — not a caret range — and bump on purpose after reading the changelog. Every version below is live on the npm registry.
package.json
Install pinned
Versioning · pin exact · Forward compatibility
8

Wire health / status monitoring

Poll /health for liveness, and watch the trust-list ETag so you notice when the signed census document (rules, accredited entries, spec version) actually moves — a 304 Not Modified means nothing changed; a 200 means re-read and re-verify.
Liveness + change detection
Versioning · conditional reads · Deprecation · detect programmatically

One-command pre-flight

Drop this in your CI or run it by hand right before the switch. It confirms liveness, prints your rate-limit headroom, flags any active deprecation, and echoes the spec version the census is pinned to. Point PHOSRA_API at production once your live keys are loaded.
preflight.sh
Output (run live against the sandbox census)
All four green, keys rotated, scopes locked, webhook verification live, and monitoring armed? You are clear to flip PHOSRA_API and your keys to production. The request shapes are identical between sandbox and prod — only the base URL, trust root, and key change.

Next steps

Production Accreditation

The governance gate: get your entry onto the production Trust List.

Authentication

Test vs live keys, scoping, and zero-downtime rotation.

Webhooks

Signed event catalog and signature verification in four languages.

Deprecation & Sunset

The advance-notice window and the headers that carry it.

Rate limits

The window headers and a copy-paste backoff loop.

Versioning

Pin the API path, spec version, dated editions, and SDK semver.