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

# Readiness: GET /api/phosra/status

> Every /api/phosra/* route returns an opaque 503 PHOSRA_NOT_READY. The readiness endpoint names which of thirteen preconditions is outstanding, and what you do about it.

# When everything returns 503

<Info>
  **This page is about `createPlatform` from `@phosra/gatekeeper`** — the catch-all platform
  facade that mounts `/api/phosra/{status,par,authorize,token,delivery,retry}`. Everything below
  (`adapter.authorizedProviders`, `adapter.database`, `GET /api/phosra/status`, `ready()`) is that
  factory's surface. The SDK reference is [`@phosra/gatekeeper` →
  `createPlatform`](/sdks/gatekeeper).

  **It does not apply to `createConnectReceiver`** from `@phosra/gatekeeper/next`, which returns an
  object with exactly one member — `POST`. That factory mounts no status route, exposes no
  `ready()`, and has no readiness machinery at all. If you followed the
  [`createConnectReceiver` quickstart](/integration/link-platform) and are curling
  `/api/phosra/status`, you will get your framework's HTML `404` no matter which SDK version you
  install. Move to `createPlatform` before using this page.
</Info>

Your `/api/phosra/authorize` returns this and nothing else:

```json theme={null}
{"ok":false,"error":{"code":"PHOSRA_NOT_READY","message":"Phosra Link is still completing its secure platform setup.","retriable":true}}
```

That message is identical whether your credential is missing, your standing lapsed, your database
never migrated, or your signing key diverged from the census. It is deliberately opaque — it is
served to the public internet — and it is undiagnosable from outside.

**`GET /api/phosra/status` is the answer.** Same deployment, same process, same request cycle.
It always answers `200` and names the outstanding precondition.

<Note>
  **Requires `@phosra/gatekeeper` ≥ 0.8.68.** Published and live on npm. If you declare
  `^0.6.0`, npm **will not** resolve 0.8.68 — a caret on a `0.x` version pins the minor. Change the
  range to `^0.8.68`.

  If you vendored the package, remove the vendored copy first; a vendored build will not have this
  route no matter what your `package.json` says.
</Note>

```bash theme={null}
npm install @phosra/gatekeeper@^0.8.68
```

No code changes. The route is mounted by the same `phosra.next.handlers()` that already mounts
your protocol routes, and is also reachable directly at `platform.handlers.status.GET`.

***

## Read it

```bash theme={null}
curl -s https://your-app.example.com/api/phosra/status | jq
```

Real output from a deployment whose credential is not set (captured from published 0.8.68):

```json theme={null}
{
  "ok": true,
  "ready": false,
  "precondition": "CREDENTIAL_MISSING",
  "summary": "No Phosra credential is configured. The value handed to createPlatform is not a Phosra credential envelope.",
  "remedy": "Set the platform credential environment variable to the credential envelope. Re-provision this app so the credential and the trust list are minted from ONE key: POST /api/v1/developers/orgs/{orgId}/apps on the census generates the keypair, registers and claims the DID, and mints the credential from that same key, so they cannot disagree. Then set the returned credential and redeploy.",
  "checkedAt": "2026-07-27T00:56:11.060Z",
  "generation": {
    "active": false,
    "refreshing": false,
    "consecutiveFailures": 1,
    "nextAttemptAt": "2026-07-27T00:56:41.060Z"
  },
  "versions": { "gatekeeper": "0.8.68", "link": "0.7.57" }
}
```

In that same process, at that same moment, `/api/phosra/authorize` returns `503`. That is the
point: **the diagnostic is not behind the gate it explains.** A diagnostic that 503s under the
fault it describes is not a diagnostic.

### Fields

| Field                | Always present     | What it is                                                                                              |
| -------------------- | ------------------ | ------------------------------------------------------------------------------------------------------- |
| `ok`                 | yes                | Always `true` — the *endpoint* answered. Read `ready`, not this.                                        |
| `ready`              | yes                | Whether the protocol routes are serving.                                                                |
| `precondition`       | yes                | **The field to act on.** One of the thirteen codes below.                                               |
| `summary` / `remedy` | yes                | Plain-language statement and the fix.                                                                   |
| `checkedAt`          | yes                | ISO timestamp of this observation.                                                                      |
| `generation`         | yes                | Bootstrap coordinator state: `active`, `refreshing`, `consecutiveFailures`, `nextAttemptAt`.            |
| `versions`           | yes                | Resolved `gatekeeper` and `link` versions actually running. Settles "did my upgrade deploy?" instantly. |
| `platform`           | when known         | `did`, `environment`, `credentialVersion`.                                                              |
| `census`             | when known         | `origin`, `trustListIssue`.                                                                             |
| `signingKey`         | on key faults      | `kid`, `credentialPublicKey`, `censusPublicKey`, `matches`.                                             |
| `standing`           | on standing faults | The resolved trust-list standing.                                                                       |
| `database`           | on database faults | `ready` and `missing` — the SDK's own schema object names.                                              |

<Info>
  **Absent fields are absent facts.** No `signingKey` means the check never got that far, not that
  the key is fine.
</Info>

### `?probe=0`

```bash theme={null}
curl -s 'https://your-app.example.com/api/phosra/status?probe=0'
```

Reads current state **without** triggering a bootstrap attempt. Use it when you are polling, or
when you want to know whether anything has attempted bootstrap at all — `PLATFORM_GENERATION_INACTIVE`
is only observable this way.

Without `probe=0` the endpoint reuses the existing generation coordinator: a healthy platform
answers with **zero network I/O**, and an unhealthy one respects the coordinator's bounded
exponential backoff (30s base, 5min cap). **You cannot hammer the census with this endpoint.**

Non-`GET` methods return `405` with `Allow: GET`.

***

## Is it safe to expose?

Yes, and the reasoning is worth stating rather than assuming.

Every field is **already public**: DIDs are public identifiers; the trust list is world-readable
at `/.well-known/ocss/trust-list`; a signing key's *public* half is precisely the thing meant to
be published; `missing` is the SDK's own schema object names; versions are in your `package.json`.

Gating it would require distributing a **new shared secret** — the exact friction Phosra Link
exists to remove (OCSS §8.1.6 bans bearer secrets) — and would withhold the answer from the
person most likely to need it: a partner debugging your deployment from outside it.

<Warning>
  **Secret containment is structural, not hopeful.** A single audited funnel converts credential
  key material into the report. It reads the public `.x` member itself, so no caller can pass a
  seed under the name `x`, and it **refuses outright** if the bytes it is about to publish are
  byte-identical to the private seed. The endpoint cannot emit your seed, your private key, or your
  credential bytes.
</Warning>

***

## The thirteen preconditions

<AccordionGroup>
  <Accordion title="PLATFORM_READY — everything passed" icon="circle-check">
    **Summary.** Every Phosra precondition passed. The protocol routes are serving.

    **Do.** Nothing. If a protocol route is still failing, the fault is downstream of readiness —
    read the `correlationId` in the route's own error body.

    <Warning>
      **`PLATFORM_READY` is not "the integration works."** Three things this endpoint structurally
      cannot see, all of which break a ceremony *after* boot:

      * **Your `profiles_url` may be a 404.** The directory check verifies the URL's *origin*, never
        that it answers — and the catch-all does **not** serve a profiles route,
        [you do](/sdks/gatekeeper#2-the-profiles-endpoint-you-must-serve). A live production platform
        is reporting `PLATFORM_READY` today with a `profiles_url` that returns
        `404 PHOSRA_ROUTE_NOT_FOUND`. Curl yours.
      * **Your worker may not be running.** Readiness reports the HTTP process. Delivery happens only
        in the worker pass, so a platform with no worker looks ready and never finishes a connection.
      * **Your DID may not be on the census's consent-attestation roster**, in which case the
        provider's consent attestation naming your app is refused `403 failed binding: app_ref` and no
        ceremony ever reaches you. That is a census-side operator setting — ask Phosra.
    </Warning>
  </Accordion>

  <Accordion title="CREDENTIAL_MISSING — no credential configured" icon="key">
    **Summary.** No Phosra credential is configured. The value handed to `createPlatform` is not a
    Phosra credential envelope.

    **Cause.** `PHOSRA_CREDENTIAL` is unset, empty, or holds something that is not an envelope
    (envelopes start `phosra_cred_v<n>.`). A very common shape: the variable exists in your dashboard
    but was never rebuilt into the image.

    **Do.** Set it to the `credential` value you were issued and redeploy. Confirm the deploy
    actually rebuilt — `versions` in this same response tells you which SDK is running.

    <Note>
      **Where a platform credential comes from, honestly.** The `remedy` string above names
      [`POST /developers/orgs/{orgId}/apps`](/platform/create-app), and that funnel is real — but it
      is live only on the Phosra-internal staging sandbox census, and a freshly self-registered DID is
      `provisional` while issuance requires `accredited`. **Today a platform credential is
      operator-issued:** email [developers@phosra.com](mailto:developers@phosra.com) with your DID (or
      desired display name), your canonical application origin, and sandbox-or-production. See
      [Getting a platform credential](/sdks/gatekeeper#getting-a-platform-credential).
    </Note>
  </Accordion>

  <Accordion title="CREDENTIAL_UNPARSEABLE — envelope present but will not bind" icon="file-circle-xmark">
    **Summary.** A Phosra credential envelope is configured but could not be parsed or bound to this
    environment.

    **Causes, in the order worth checking.**

    1. **Truncated on copy** — envelopes are long and survive no line-wrapping.
    2. **Environment mismatch** — a sandbox credential in a production deployment, or vice versa.
    3. **Manifest drift.** The credential pins the environment manifest's `id` *and* a
       `config_digest` computed over the manifest's whole `configuration` object. If any part of that
       configuration changes — `sdk_minimum`, origins, rule-registry edition, root key id — **every
       previously issued credential fails to bind at once.** This is a global condition, not a
       per-deployment one: if several unrelated platforms broke simultaneously, look here first.

    **Do.** Re-copy whole. If (3), the credential must be re-minted against the current manifest —
    an SDK upgrade will not help.
  </Accordion>

  <Accordion title="ENVIRONMENT_MANIFEST_UNAVAILABLE — cannot fetch or verify the manifest" icon="cloud-slash">
    **Summary.** The signed Phosra environment manifest could not be fetched or verified against the
    credential's pins.

    **Cause.** Egress blocked to the management origin, DNS failure, or a credential whose pinned
    manifest signer does not match what that origin serves.

    **Do.** Confirm this deployment can reach the management origin over HTTPS, and that the
    credential's environment matches the deployment.

    The manifest is **not JSON, and not a bare compact JWS**: it is a compact JWS behind a
    `phosra_env_v1.` envelope prefix, so it splits into **four** dot-separated parts, not three. A
    standard JWS decoder — or `cut -d. -f2` — decodes the wrong segment and hands you a base64 error.
    The payload is part **3**:

    ```bash theme={null}
    curl -s https://prodapi.phosra.com/.well-known/phosra/environment-manifest-v1 \
    | cut -d. -f3 | base64 -d 2>/dev/null \
    | jq '{manifest_id, expires_at, configuration: {services, trust_list, routing, redirect_policy, sdk_minimum}}'
    ```

    ```json theme={null}
    {
      "manifest_id": "production-bootstrap-current",
      "expires_at": "2026-08-26T11:45:24Z",
      "configuration": {
        "services": {
          "census_origin": "https://phosra-api-prod-bootstrap-production.up.railway.app",
          "directory_origin": "https://phosra-api-prod-bootstrap-production.up.railway.app",
          "management_origin": "https://dashboard.phosra.com"
        },
        "trust_list": {
          "path": "/.well-known/ocss/trust-list",
          "root_key_id": "root-prod-bootstrap-2026-07",
          "root_pin_id": "ocss-root-prod-bootstrap"
        },
        "routing": { "operating_router_did": "did:ocss:phosra-router", "schema_version": 1 },
        "redirect_policy": { "allow_http_loopback": false, "http_loopback_hosts": [] },
        "sdk_minimum": { "connect": "0.2.0", "gatekeeper": "0.8.6", "link": "0.7.6" }
      }
    }
    ```

    That one command also hands you the two values the other accordions need: the `census_origin`
    your credential is bound to, and the `operating_router_did` whose standing gates your boot.

    <Note>
      **`expires_at` is real.** The manifest is re-signed periodically; a deployment that cached a
      verified environment and then lost egress will eventually fail closed here rather than serve on
      stale trust.
    </Note>
  </Accordion>

  <Accordion title="TRUST_LIST_UNVERIFIABLE — cannot reach or verify the census" icon="list-check">
    **Summary.** The census trust list could not be fetched or verified to the pinned OCSS root.

    **Cause.** Census unreachable, **or** the credential pins a root this census does not sign with.
    The second is the nastier one and looks like a network problem.

    **Do.** Fetch the list yourself and compare the root against what your credential pins:

    ```bash theme={null}
    curl -s https://prodapi.phosra.com/.well-known/ocss/trust-list | jq '{key_id, alg}'
    # → { "key_id": "root-prod-bootstrap-2026-07", "alg": "ed25519" }
    ```

    Production's root public X is `824vsCATBxyUiA-znpGx01N48NNs_3gPE3M7f7vIEaI`. **Pin the public X,
    not the key id.** A credential pinning the retired `root-prod-2026-06` fails closed on every
    current document — correctly.
  </Accordion>

  <Accordion title="PLATFORM_SIGNING_KEY_UNPUBLISHED — census publishes no such kid" icon="magnifying-glass">
    **Summary.** The census publishes no signing key under this platform's active key id.

    **Cause.** Your credential names a `kid` that is simply not on your trust-list entry — often
    after a rotation that added a new kid and dropped the old one, while a deployment still holds a
    credential naming the dropped one.

    **Do.** Read `signingKey.kid` from the response, then list what the census actually publishes:

    ```bash theme={null}
    curl -s https://prodapi.phosra.com/.well-known/ocss/trust-list \
    | jq -r '.document | fromjson | .entries[] | select(.did=="did:ocss:YOUR-DID")
             | .jwks.signing_keys[] | "\(.kid)  \(.x)"'
    ```

    <Note>
      `document` is served as a **JSON string**, not a nested object — it is the exact byte sequence
      the root signature covers. Hence the `fromjson`. Parsing it any other way changes the bytes and
      breaks verification.
    </Note>

    Real output for a live entry:

    ```
    link-1  47tjRF8D8DFYQ9Kl7F3hg7qEA9PnliCuDs4xhlSuUQM
    2026-07  AZMIh9qxtx0nN4bXfj2f60_mGhl0cryDS5vCrKBZew4
    authority-1  v7XsJac1_fJqtdYIcg0qkuOiR3iVVLuZ1K6xH4qoGj0
    ```

    Publish that kid on the entry, or [re-provision](/platform/create-app) so credential and trust
    list come from one key.
  </Accordion>

  <Accordion title="PLATFORM_SIGNING_KEY_MISMATCH — the divergence this endpoint exists for" icon="code-compare">
    **Summary.** The credential's active signing key is **not** the key the census publishes under
    that key id. The credential and the trust list have diverged.

    **This is the failure class.** The response prints both public halves side by side:

    ```json theme={null}
    "signingKey": {
      "kid": "did:ocss:example#link-1",
      "credentialPublicKey": "…",
      "censusPublicKey": "…",
      "matches": false
    }
    ```

    **An SDK upgrade cannot fix this.** Both sides of the comparison are data. The credential embeds
    one key; the census publishes another; nothing structurally forced them to agree, because they
    were minted separately.

    **Do.** [Re-provision through `/apps`](/platform/create-app), which generates the keypair and
    mints the credential **from that same key**, so they cannot disagree. Then set the returned
    credential and redeploy. See the [divergence note](/integration/credential-divergence) for how
    this happens and who is exposed.
  </Accordion>

  <Accordion title="PLATFORM_STANDING_NOT_ACCREDITED — your standing lapsed" icon="certificate">
    **Summary.** This platform's trust-list standing is not active and accredited.

    **Cause.** Most often a **conformance attestation that passed its TTL** and needs re-issuing. Also:
    the entry was revoked, suspended, or `valid_through` elapsed.

    **Do.** Read the `standing` object in the response, then confirm against the census:

    ```bash theme={null}
    curl -s https://prodapi.phosra.com/.well-known/ocss/trust-list \
    | jq -r '.document | fromjson | .entries[] | select(.did=="did:ocss:YOUR-DID")
             | "\(.status)  \(.tier)  \(.role)  valid_through=\(.valid_through)"'
    # → active  accredited  enforcement-agent  valid_through=2027-01-22T05:00:29Z
    ```

    You want `active` and `accredited`. Restoring standing is an operator action — attestations are
    issued by a verifying agency, not self-served.

    <Note>
      Because a live recorder survives a successful boot, this code also catches a **mid-life**
      divergence — a rotation or an attestation lapse that happened *after* your app booted — not only
      a boot-time one. A later success clears it rather than reporting it forever.
    </Note>
  </Accordion>

  <Accordion title="AUTHORIZED_PARTY_NOT_ACCREDITED — a counterparty lost standing" icon="handshake-slash">
    **Summary.** A configured counterparty is not active + accredited with the required role on the
    census.

    **Your credential is fine.** You are failing on someone else's trust-list entry. There are
    **two** distinct counterparties behind this one code, and only one of them is yours.

    **Cause 1 — a DID in `adapter.authorizedProviders`.** Every entry must be `status: active`,
    `tier: accredited` **and** `role: enforcement-agent`.

    ```bash theme={null}
    DID=did:ocss:custo
    curl -s https://prodapi.phosra.com/.well-known/ocss/trust-list \
    | jq -r --arg d "$DID" '.document | fromjson | .entries[] | select(.did==$d)
             | "\($d)  \(.status)  \(.tier)  \(.role)  valid_through=\(.valid_through)"'
    # → did:ocss:custo  active  accredited  enforcement-agent  valid_through=2027-01-23T12:03:46Z
    ```

    The most common real cause is a **conformance attestation that passed its TTL** on a partner's
    entry, which silently downgrades `accredited` to `verified`.

    **Cause 2 — the census's operating router, which you never configured.** `createPlatform`
    resolves the census's **operating router** from the signed environment manifest
    (`configuration.routing.operating_router_did` — `did:ocss:phosra-router` on every current
    census) and hard-fails boot if that entry is not active + accredited. The router is the signer
    whose signature is on every enforcement profile you consume, so if it lapses nothing can be
    trusted and nothing boots.

    ```bash theme={null}
    curl -s https://prodapi.phosra.com/.well-known/ocss/trust-list \
    | jq -r '.document | fromjson | .entries[] | select(.did=="did:ocss:phosra-router")
             | "\(.status)  \(.tier)  role=\(.role)"'
    # → active  accredited  role=null
    ```

    <Warning>
      **The router carries no `role`** — only `status` and `tier` are read for it. Do **not** apply the
      `enforcement-agent` check to the router; it will look broken when it is fine.

      **And if the router is the failing party, that is not a fault you can fix.** You do not configure
      its DID, its standing, or its attestation. Report it with the `versions` block from this
      response rather than changing your own configuration.
    </Warning>
  </Accordion>

  <Accordion title="PLATFORM_DIRECTORY_UNAVAILABLE — your own directory entry does not resolve" icon="signs-post">
    **Summary.** This platform's own directory presentation could not be resolved.

    Before it boots, the SDK fetches **its own** row from the census and compares it to your
    credential on **six values**, five of them byte-for-byte. Any one of them off by a character is
    this code, and every `/api/phosra/*` route then serves an opaque 503 — with a correct credential,
    correct standing and a correct origin.

    | Field               | Must equal                                                   |
    | ------------------- | ------------------------------------------------------------ |
    | `directory_version` | the integer `1`                                              |
    | `name`              | your credential's `display.name`, **byte for byte**          |
    | `authorize_url`     | `{applicationOrigin}/api/phosra/authorize`                   |
    | `par_url`           | `{applicationOrigin}/api/phosra/par`                         |
    | `token_url`         | `{applicationOrigin}/api/phosra/token`                       |
    | `profiles_url`      | same **origin** as the credential, any path, no query string |

    **Do.** Read the row and check every field, not just one:

    ```bash theme={null}
    curl -s https://prodapi.phosra.com/api/v1/providers/did:ocss:YOUR-DID/connect | jq
    ```

    Three causes, in the order worth checking:

    1. **Origin drift** — the application origin in the credential is not where the app is actually
       served: a preview URL, a new custom domain, a moved Railway/Vercel host. The credential must
       be **re-issued** for the new origin *and* the row re-published; moving one alone leaves you
       permanently 503.
    2. **Display-name drift** — `name` differs from the credential's display name. This is invisible
       in every other check and fatal here.
    3. **An unexpected member in the row.** The row is a **closed set**: beyond the six required
       fields only `scopes`, `icon_url`, `connect_url`, `provisioning_form` and
       `profile_management_url` are permitted. An extra member fails the whole row rather than being
       ignored.

    A `404 provider connect config not available` means no directory entry exists for that DID at
    all.

    **Publishing or correcting the row** is `PATCH /api/v1/platforms/{did}/connect` — RFC-9421
    signed, self-scoped, JSON-merge semantics (`null` deletes a member), never rotates labels or
    secrets. See [the directory-row section of the gatekeeper
    reference](/sdks/gatekeeper#1-your-own-directory-row). At onboarding an
    operator seeds it for you to match the credential they issue.
  </Accordion>

  <Accordion title="PLATFORM_COMPOSITION_FAILED — SDK-internal" icon="bug">
    **Summary.** Trust and directory verification passed, but platform composition failed.

    **Do.** This one is ours, not yours. Report it with the correlation id from the `onDiagnostic`
    hook, plus the `versions` block from this response.

    <Note>
      **You only have a correlation id if you wired the hook.** `onDiagnostic` is a first-class option
      on `createPlatform` and is absent from most quickstart snippets:

      ```ts theme={null}
      createPlatform({
        credential,
        onDiagnostic: (d) => console.error(JSON.stringify(d)),  // { operation, subcode, retryable, correlationId, causeClass }
        adapter: { /* … */ },
      })
      ```

      The payload is content-free. It is also the **only** channel for two whole failure classes that
      never reach this endpoint at all — `operation: "materialization"` (a delivery pass failed
      mid-flight) and `operation: "target_aggregate_lifecycle"`. See
      [`onDiagnostic`](/sdks/gatekeeper#the-ondiagnostic-hook).
    </Note>
  </Accordion>

  <Accordion title="PLATFORM_DATABASE_NOT_READY — your Postgres" icon="database">
    **Summary.** The package-owned schema did not migrate or did not report ready.

    **Cause.** Entirely your side: unreachable Postgres, or a role that cannot create the objects the
    package owns.

    **Do.** Read `database.missing` — it lists the exact object names still absent. Confirm the `Pool`
    handed to `adapter.database` points at a reachable Postgres the app is allowed to migrate, then
    retry.
  </Accordion>

  <Accordion title="PLATFORM_GENERATION_INACTIVE — nothing has tried yet" icon="hourglass-start">
    **Summary.** No verified platform generation is active and no bootstrap attempt has been recorded
    yet.

    **Cause.** Either you passed `?probe=0` before anything ran, or the process genuinely has not
    attempted bootstrap.

    **Do.** Re-read **without** `probe=0` to trigger one bounded attempt, then read the real code.
  </Accordion>
</AccordionGroup>

***

## A 2am triage order

<Steps>
  <Step title="Confirm the endpoint even exists">
    `curl -s .../api/phosra/status`, and read the *shape* of the failure — the three cases have
    three different fixes:

    * **`404` with `{"error":{"code":"PHOSRA_ROUTE_NOT_FOUND"}}`** — the SDK is mounted and
      answering, but predates 0.8.68. Upgrade.
    * **Your framework's HTML `404`** — nothing Phosra is mounted at that path. Either the
      catch-all is not wired, **or you built with the wrong factory**:
      `createConnectReceiver` mounts a single `POST` and no status route, so no version of the
      SDK will ever answer here. Check which factory your singleton calls before you touch
      `package.json`.
    * **`307`/`302` to a login page** — your own auth middleware is shadowing `/api/phosra/*`.
      Exempt that prefix.
  </Step>

  <Step title="Read `precondition`, not the logs">
    It names the outstanding condition directly. `remedy` names the fix.
  </Step>

  <Step title="Check `versions`">
    Confirms which SDK is actually running — the fastest way to catch a deploy that did not
    rebuild.
  </Step>

  <Step title="If it is a key or standing fault, verify against the census yourself">
    The trust list is public. Compare `signingKey.censusPublicKey` with what
    `/.well-known/ocss/trust-list` publishes for your DID.
  </Step>

  <Step title="If it is a divergence, re-provision — do not retry">
    `PLATFORM_SIGNING_KEY_MISMATCH` never heals on its own. See
    [the divergence note](/integration/credential-divergence).
  </Step>
</Steps>

***

## What readiness cannot check

Readiness proves the **boot** preconditions. Four things break a live ceremony and are invisible
here, so check them by hand once per deployment:

```bash theme={null}
# 1. Your published profiles endpoint answers. 401 is correct; 404 means you never wrote it.
curl -s -o /dev/null -w 'profiles %{http_code}\n' https://your-app.example.com/api/ocss/profiles

# 2. Your directory row still matches your credential's origin and display name.
curl -s https://prodapi.phosra.com/api/v1/providers/did:ocss:YOUR-DID/connect | jq

# 3. Your worker process is alive. Delivery happens only in the worker pass.
#    (whatever health surface you gave it — phosra.worker.status() is the source)

# 4. onDiagnostic is wired. Materialization and lifecycle failures reach no other channel.
```

The fifth is not yours to check: your DID must be on the census's consent-attestation roster
before a provider can land the attestation that starts a ceremony against your platform. If your
platform is `PLATFORM_READY` and nothing ever arrives, ask Phosra to confirm it.

<Card title="@phosra/gatekeeper — createPlatform" icon="cube" href="/sdks/gatekeeper" horizontal>
  The full SDK reference: the directory row, the profiles endpoint, `authorizedProviders`,
  framework-agnostic mounting, the worker, and how to obtain a credential.
</Card>
