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

# Generate a client in your language

> Generate a typed Phosra client for TypeScript, Python, Go, Java, or any language straight from the hosted OpenAPI spec — real commands, run against the live sandbox, with a generated-client call that returns 201.

Phosra ships a first-party [TypeScript SDK](/sdks/typescript). Every other language
talks to the same plain-JSON REST API — and because that API is described by a
published **OpenAPI 3.1** document, you can generate a fully-typed client in your
language in about a minute. This page runs the real generators end-to-end against the
[live sandbox](https://phosra-api-sandbox-production.up.railway.app) and pastes the
actual output, including one generated-client call that returns `201`.

<Info>
  **Verified copy-paste.** Every command on this page was run on **2026-07-06** against
  the hosted spec at `https://phosra-api-sandbox-production.up.railway.app/openapi.yaml`
  with `openapi-generator-cli` **7.23.0**, `openapi-typescript` **7.13.0**, and
  `openapi-fetch` **0.13**. The TypeScript, Python, and Go clients each made the same
  live `POST /setup/quick` call and printed the same three lines:
  `Emma's Family` / `preteen` / `20`.
</Info>

## Which spec do I generate from?

Phosra publishes **three** OpenAPI documents. Pick the one that matches what you are
building — generating from the wrong spec gives you endpoints you can't call.

| Spec                                             | Generate from                                                                                              | Use it when you are…                                                                                                                                                                                                                  |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Product API** (`openapi.yaml`)                 | `https://phosra-api-sandbox-production.up.railway.app/openapi.yaml`                                        | Building a **parental-controls app** — families, children, policies, rules, enforcement, quick-setup. This is the one almost everyone wants. Also mirrored at [`docs.phosra.com/openapi.yaml`](https://docs.phosra.com/openapi.yaml). |
| **Control plane** (`openapi.control-plane.yaml`) | [`https://docs.phosra.com/openapi.control-plane.yaml`](https://docs.phosra.com/openapi.control-plane.yaml) | Managing your **provider account** — developer orgs, API keys, federation, advisors. Server-to-server, `phosra_` key required.                                                                                                        |
| **Data plane** (`openapi.data-plane.yaml`)       | [`https://docs.phosra.com/openapi.data-plane.yaml`](https://docs.phosra.com/openapi.data-plane.yaml)       | Building an **OCSS gatekeeper / resolver** — signed profile reads, binding, §8.3.8 confirmations. See the [signing caveat](#the-data-plane-signing-caveat) below before you generate.                                                 |

<Note>
  The sandbox host serves the **product API** spec (`/openapi.yaml`) so generated
  clients can point straight at a live server. The two split specs
  (`openapi.control-plane.yaml`, `openapi.data-plane.yaml`) are served from the docs
  site. All three are the same documents that drive the [API Reference](/api-reference/overview).
</Note>

## Prerequisites

<CardGroup cols={2}>
  <Card title="For TypeScript" icon="js">
    **Node.js 18+**. Uses `openapi-typescript` (types) + `openapi-fetch` (runtime). No
    Java, no code to vendor — types only.
  </Card>

  <Card title="For Python / Go / Java / others" icon="java">
    **Java 11+** on your `PATH` (the `openapi-generator` engine is a JAR) plus **Node**
    to run `npx @openapitools/openapi-generator-cli`. Check with `java -version`.
  </Card>
</CardGroup>

## TypeScript — `openapi-typescript` + `openapi-fetch`

The idiomatic TS path is **types-only** generation paired with a tiny typed fetch
wrapper — no generated client code to vendor, and full autocomplete on every path,
body, and response.

<Steps>
  <Step title="Generate the types">
    ```bash theme={null}
    npx openapi-typescript \
      https://phosra-api-sandbox-production.up.railway.app/openapi.yaml \
      -o ./phosra.d.ts
    ```

    Real output:

    ```text theme={null}
    ✨ openapi-typescript 7.13.0
    🚀 https://phosra-api-sandbox-production.up.railway.app/openapi.yaml → phosra.d.ts [430.5ms]
    ```

    You now have a `phosra.d.ts` describing all 80 paths. The `/setup/quick` entry looks
    exactly like this (excerpt from the real generated file):

    ```typescript phosra.d.ts (generated) theme={null}
    "/setup/quick": {
        // …
        /**
         * One-step onboarding
         * @description Creates a family (or uses existing), adds a child,
         *   generates age-appropriate policy rules, and activates the policy.
         */
        post: {
            requestBody: {
                content: {
                    "application/json": components["schemas"]["QuickSetupRequest"];
                };
            };
            responses: {
                /** @description Setup complete */
                201: {
                    content: {
                        "application/json": components["schemas"]["QuickSetupResponse"];
                    };
                };
                // …
            };
        };
    };
    ```
  </Step>

  <Step title="Make a typed call">
    ```bash theme={null}
    npm install openapi-fetch
    ```

    ```typescript run.ts theme={null}
    import createClient from "openapi-fetch";
    import type { paths } from "./phosra.d.ts";

    const client = createClient<paths>({
      baseUrl: "https://phosra-api-sandbox-production.up.railway.app/api/v1",
    });

    // Fully typed: the body, the path, and `data` below are all inferred from the spec.
    const { data, error } = await client.POST("/setup/quick", {
      body: { child_name: "Emma", birth_date: "2016-03-15", strictness: "recommended" },
    });
    if (error) throw error;

    console.log("family:", data.family?.name);
    console.log("age_group:", data.age_group);
    console.log("rules_enabled:", data.rule_summary?.total_rules_enabled);
    ```

    Run it (Node 22+ strips the types natively):

    ```bash theme={null}
    node --experimental-strip-types run.ts
    ```

    Real output:

    ```text theme={null}
    family: Emma's Family
    age_group: preteen
    rules_enabled: 20
    ```
  </Step>
</Steps>

<Tip>
  Prefer a batteries-included, hand-maintained client? Skip generation and use the
  first-party [`@phosra/sdk`](/sdks/typescript) (`PhosraClient`) — it wraps the same
  API with retries and token management.
</Tip>

## Python — `openapi-generator-cli`

<Steps>
  <Step title="Generate the client">
    ```bash theme={null}
    npx @openapitools/openapi-generator-cli generate \
      -i https://phosra-api-sandbox-production.up.railway.app/openapi.yaml \
      -g python \
      -o ./python-client \
      --additional-properties=packageName=phosra_client,projectName=phosra-client
    ```

    This writes a full installable package: one `*_api.py` module per tag
    (`quick_setup_api.py`, `families_api.py`, `policies_api.py`, …) plus Pydantic models
    for every schema (`QuickSetupRequest`, `QuickSetupResponse`, …).
  </Step>

  <Step title="Install and call the sandbox">
    ```bash theme={null}
    python3 -m venv .venv && . .venv/bin/activate
    pip install ./python-client
    ```

    ```python run_client.py theme={null}
    from phosra_client import ApiClient, Configuration, QuickSetupApi
    from phosra_client.models.quick_setup_request import QuickSetupRequest

    cfg = Configuration(
        host="https://phosra-api-sandbox-production.up.railway.app/api/v1"
    )
    with ApiClient(cfg) as api_client:
        api = QuickSetupApi(api_client)
        resp = api.setup_quick_post(QuickSetupRequest(
            child_name="Emma", birth_date="2016-03-15", strictness="recommended",
        ))
        print("family:", resp.family.name)
        print("age_group:", resp.age_group)
        print("rules_enabled:", resp.rule_summary.total_rules_enabled)
    ```

    ```bash theme={null}
    python3 run_client.py
    ```

    Real output:

    ```text theme={null}
    family: Emma's Family
    age_group: preteen
    rules_enabled: 20
    ```
  </Step>
</Steps>

## Go — `openapi-generator-cli`

<Steps>
  <Step title="Generate the client">
    ```bash theme={null}
    npx @openapitools/openapi-generator-cli generate \
      -i https://phosra-api-sandbox-production.up.railway.app/openapi.yaml \
      -g go \
      -o ./go-client \
      --additional-properties=packageName=phosra,isGoSubmodule=true,disallowAdditionalPropertiesIfNotPresent=false
    ```

    <Note>
      The generator writes a placeholder module path
      (`github.com/GIT_USER_ID/GIT_REPO_ID`). Edit the first line of
      `go-client/go.mod` to your real module path (below it is `example.com/phosra`) so
      you can import it.
    </Note>
  </Step>

  <Step title="Call the sandbox">
    ```go main.go theme={null}
    package main

    import (
        "context"
        "fmt"
        "log"

        phosra "example.com/phosra"
    )

    func main() {
        cfg := phosra.NewConfiguration()
        // Point the default server at the open sandbox.
        cfg.Servers[0].URL = "https://phosra-api-sandbox-production.up.railway.app/api/v1"
        client := phosra.NewAPIClient(cfg)

        req := phosra.NewQuickSetupRequest("Emma", "2016-03-15")
        req.SetStrictness("recommended")

        resp, _, err := client.QuickSetupAPI.SetupQuickPost(context.Background()).
            QuickSetupRequest(*req).Execute()
        if err != nil {
            log.Fatal(err)
        }
        family := resp.GetFamily()
        summary := resp.GetRuleSummary()
        fmt.Println("family:", family.GetName())
        fmt.Println("age_group:", resp.GetAgeGroup())
        fmt.Println("rules_enabled:", summary.GetTotalRulesEnabled())
    }
    ```

    ```bash theme={null}
    go mod tidy && go run .
    ```

    Real output:

    ```text theme={null}
    family: Emma's Family
    age_group: preteen
    rules_enabled: 20
    ```
  </Step>
</Steps>

## Java and everything else

The same `openapi-generator-cli` produces clients for
[60+ languages](https://openapi-generator.tech/docs/generators) — swap the `-g` flag.
Java, for example:

```bash theme={null}
npx @openapitools/openapi-generator-cli generate \
  -i https://phosra-api-sandbox-production.up.railway.app/openapi.yaml \
  -g java \
  -o ./java-client \
  --additional-properties=library=native,invokerPackage=com.phosra.client,apiPackage=com.phosra.client.api,modelPackage=com.phosra.client.model
```

Other common targets: `-g csharp`, `-g rust`, `-g kotlin`, `-g php`, `-g ruby`,
`-g swift5`. List every generator with
`npx @openapitools/openapi-generator-cli list`.

## Authenticating a generated client

The verified calls above hit the **open sandbox** `POST /setup/quick`, which needs no
key — that is the sandbox-first path. Real product routes live under `/developer/*` and
need a `phosra_test_` (sandbox) or `phosra_live_` (production) key sent as
**`Authorization: Bearer`**. Wire it into the generated client's config:

<CodeGroup>
  ```typescript openapi-fetch theme={null}
  const client = createClient<paths>({
    baseUrl: "https://phosra-api-sandbox-production.up.railway.app/api/v1",
    headers: { Authorization: `Bearer ${process.env.PHOSRA_API_KEY}` },
  });
  ```

  ```python Python theme={null}
  cfg = Configuration(
      host="https://phosra-api-sandbox-production.up.railway.app/api/v1",
      access_token=os.environ["PHOSRA_API_KEY"],  # sent as Authorization: Bearer
  )
  ```

  ```go Go theme={null}
  cfg := phosra.NewConfiguration()
  cfg.Servers[0].URL = "https://phosra-api-sandbox-production.up.railway.app/api/v1"
  cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("PHOSRA_API_KEY"))
  ```
</CodeGroup>

<Card title="Get a sandbox key" icon="key" href="https://dashboard.phosra.com/dashboard/developers/keys">
  Mint a `phosra_test_…` key on the **Keys** page. See [Authentication](/authentication)
  for the full header rules (`Authorization: Bearer` is canonical; `X-Api-Key` is
  accepted as an equivalent).
</Card>

## The data-plane signing caveat

If you generate from **`openapi.data-plane.yaml`**, be aware that those endpoints are
**not plain REST**:

<Warning>
  A generated client gives you the correct **wire shapes** for the data plane, but it
  will **not** produce valid requests on its own. Profile `GET`s are **RFC 9421-signed**
  by the resolver, binding `POST`s require an **accredited caller signature**, and
  profile responses are **root-verifiable signed documents**. Signing and verification
  are cryptographic steps the generator does not emit.
</Warning>

For anything on the data plane, use the maintained SDKs that implement the signing:

* **[`@openchildsafety/ocss`](https://www.npmjs.com/package/@openchildsafety/ocss)** —
  RFC 9421 sign/verify, sealed envelopes, trust-list verification.
* **[`@phosra/gatekeeper`](https://www.npmjs.com/package/@phosra/gatekeeper)** — the
  platform-side decision engine that drives the data plane end-to-end (verify profiles,
  enforce, send §8.3.8 receipts).

Use a generated data-plane client only for reading response types into your own models,
not for making the signed calls. The **product API** (`openapi.yaml`) has no such
caveat — a generated client calls it directly, as shown above.

## Pin your generator version

Generators evolve; output can shift between major versions. For reproducible builds,
pin the exact version instead of letting `npx` pull `latest`:

```bash theme={null}
# Pin openapi-generator
npx @openapitools/openapi-generator-cli@2.23.4 generate ...   # CLI wrapper
# (the wrapper then downloads generator engine 7.23.0 — pin it in openapitools.json)

# Pin openapi-typescript
npx openapi-typescript@7.13.0 ...
```

<Note>
  The spec is versioned by the `/api/v1` path and evolves additively (see
  [Versioning](/versioning)). Re-run the generator after a spec change to pick up new
  fields; a regeneration never silently changes an existing field's type without a
  version bump.
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Zero-to-enforcement against the open sandbox — no key needed.
  </Card>

  <Card title="TypeScript SDK" icon="js" href="/sdks/typescript">
    The hand-maintained `PhosraClient` if you'd rather not generate.
  </Card>

  <Card title="Authentication" icon="key" href="/authentication">
    Keys, headers, and the `phosra_test_` vs `phosra_live_` split.
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/overview">
    Every endpoint, field, and error — the same spec you just generated from.
  </Card>
</CardGroup>
