> ## 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.

# API playground

> Run real requests against the live Phosra sandbox — three ways: the inline "Try it" on every reference page, the hosted request runner, and copy-paste cURL. Every call is keyless and safe to repeat.

You do not have to leave the docs to make your first call. Phosra exposes an always-on
**hosted sandbox** — a full copy of the API seeded with a demo family and a set of accredited
reference providers — and every request on this page goes to it live. No key, no signup, nothing
you do touches a real family.

<Info>
  Base URL for every call below:

  ```bash theme={null}
  export SANDBOX="https://phosra-api-sandbox-production.up.railway.app"
  ```

  Swap it for `https://prodapi.phosra.com` and add a `phosra_live_…` key when you go to
  production — the request shapes are identical.
</Info>

## Three ways to try it

<CardGroup cols={3}>
  <Card title="Inline “Try it”" icon="play">
    Every endpoint in the [API Reference](/api-reference/overview) has a **Try it** panel — fill in
    parameters, hit send, read the response, right next to the docs.
  </Card>

  <Card title="Hosted request runner" icon="bolt" href="https://phosra.com/developers/api-playground">
    A standalone in-page runner on phosra.com that fires real keyless calls at the sandbox and
    shows status, latency, and body.
  </Card>

  <Card title="Copy-paste cURL" icon="terminal">
    Every snippet below is verbatim and runs as-is in your terminal against the live sandbox.
  </Card>
</CardGroup>

## The hosted request runner

The [**API playground**](https://phosra.com/developers/api-playground) on phosra.com is an
in-page request runner. Pick an operation, press **Send**, and it makes a real HTTP round-trip to
the hosted sandbox and shows you the true status code, latency, and JSON body — nothing is mocked.

<Frame caption="A real self-registration against the live sandbox — HTTP 200 in 97 ms, returning a fresh provisional Trust List entry.">
  <img src="https://mintcdn.com/phosra/o0ansqUg4hqAQihW/images/playground-live-run.jpg?fit=max&auto=format&n=o0ansqUg4hqAQihW&q=85&s=91cd57f85b26142a22bb353683a38b56" alt="The Phosra API playground showing a live 200 OK self-register response from the hosted sandbox" width="1280" height="1200" data-path="images/playground-live-run.jpg" />
</Frame>

The runner proxies each call server-side through a fixed allow-list of keyless sandbox
operations, so it works from any browser without tripping CORS — and it can never be pointed at
production or an arbitrary URL.

## Run it yourself, right now

These three calls need **no key** and are safe to repeat. Each response below is **verbatim live
output**, captured while writing this page.

<Steps>
  <Step title="Confirm the sandbox is up">
    ```bash theme={null}
    curl -s "$SANDBOX/health"
    ```

    **Real response (200):**

    ```json theme={null}
    { "status": "ok" }
    ```
  </Step>

  <Step title="Read the signed Trust List">
    The Trust List is the Ed25519-signed source of truth for who is accredited. Verify the signature
    before you trust any entry inside it.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -s "$SANDBOX/.well-known/ocss/trust-list" \
        | jq '{alg, key_id, entries: (.document | fromjson | .entries | length)}'
      ```

      ```typescript TypeScript theme={null}
      const res = await fetch(`${SANDBOX}/.well-known/ocss/trust-list`);
      const list = await res.json();
      const doc = JSON.parse(list.document);        // `document` is a signed JSON string
      console.log({ alg: list.alg, key_id: list.key_id, entries: doc.entries.length });
      ```

      ```python Python theme={null}
      import json, requests
      list_ = requests.get(f"{SANDBOX}/.well-known/ocss/trust-list", timeout=30).json()
      doc = json.loads(list_["document"])           # `document` is a signed JSON string
      print({"alg": list_["alg"], "key_id": list_["key_id"], "entries": len(doc["entries"])})
      ```
    </CodeGroup>

    **Real response (200):**

    ```json theme={null}
    {
      "alg": "ed25519",
      "key_id": "root-sandbox-2026-06",
      "entries": 140
    }
    ```

    <Note>
      `entries` is a **live, growing number** — every self-registration (next step) adds one, so expect
      a value at or above the one shown here. Verify the signature and each entry's tier rather than
      asserting on the total.
    </Note>
  </Step>

  <Step title="Self-register a provisional DID">
    You do not need anyone's approval to start testing signed flows. Mint an Ed25519 keypair, post
    the raw public key, and the census adds you to the sandbox Trust List at the **`provisional`**
    tier.

    ```bash theme={null}
    # Mint a keypair and extract the raw 32-byte public key as base64url (unpadded)
    openssl genpkey -algorithm ed25519 -out sandbox-key.pem
    PUB=$(openssl pkey -in sandbox-key.pem -pubout -outform DER \
      | tail -c 32 | base64 | tr '+/' '-_' | tr -d '=')

    # Use a UNIQUE DID each run — a fixed DID 409s (did_already_registered) after the first call
    DID="did:ocss:dx-playground-$(date +%s)"

    curl -s -X POST "$SANDBOX/api/v1/advisors/self-register" \
      -H "Content-Type: application/json" \
      -d "{\"did\":\"$DID\",\"public_key_b64url\":\"$PUB\",\"roles\":[\"provider\"]}" \
      | jq .
    ```

    **Real response (200):**

    ```json theme={null}
    {
      "advisor_id": "f00a613f-32af-44c1-9627-8fbbf0f423f1",
      "did": "did:ocss:dx-playground-1783319251",
      "key_id": "did:ocss:dx-playground-1783319251#2026-07",
      "kid": "2026-07",
      "published_key_x": "7ZX9F56ceeFxORPaCi0Ul_YchgRJxMcC7fJCCnVHH18",
      "trust_tier": "provisional"
    }
    ```

    You are now on the sandbox Trust List. The `key_id` (`did#kid`) is what you sign requests with;
    the census publishes your public key so counterparties can verify you.

    <Note>
      Re-registering the **same** DID returns `409 did_already_registered` — pick a fresh DID (the
      hosted runner appends a random suffix per run for exactly this reason). Moving from `provisional`
      to `verified` or `accredited` is a governance step, not an API call — see
      [Production accreditation](/integration/production-accreditation).
    </Note>
  </Step>
</Steps>

## The inline “Try it” panel

Open any endpoint in the [API Reference](/api-reference/overview) — for example
[Create Family](/api-reference/families/create-family) — and you will see a **Try it** panel
rendered from the OpenAPI spec. It is pre-pointed at the hosted sandbox server, so you can fill in
a body, send, and read the live response without leaving the page. Endpoints that require auth
take a `phosra_test_…` key in the **Authorization** field; the keyless endpoints above need
nothing.

## What you cannot break

Everything on this page and in the inline runner hits the **sandbox**, never production:

* The sandbox is seeded with a fictional demo family (`Mia`, `Leo`, `Ava`) — no real child data.
* Self-registration lands at the `provisional` tier, which carries no weight in production.
* The base URL is hard-coded per surface; there is no way to redirect a sandbox call to
  `prodapi.phosra.com`.

When you are ready for the real thing, read [Create your account & get keys](/quickstart) and
swap the base URL.

<CardGroup cols={2}>
  <Card title="Test in the sandbox" icon="flask" href="/guides/test-in-sandbox">
    The full map of what is seeded, what is open, and how to get onto the Trust List.
  </Card>

  <Card title="Quickstart" icon="bolt" href="/quickstart">
    Zero to an enforced policy in under five minutes.
  </Card>
</CardGroup>
