Skip to main content
Phosra ships a first-party TypeScript SDK. 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 and pastes the actual output, including one generated-client call that returns 201.
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.

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.
SpecGenerate fromUse it when you are…
Product API (openapi.yaml)https://phosra-api-sandbox-production.up.railway.app/openapi.yamlBuilding 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.
Control plane (openapi.control-plane.yaml)https://docs.phosra.com/openapi.control-plane.yamlManaging 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.yamlBuilding an OCSS gatekeeper / resolver — signed profile reads, binding, §8.3.8 confirmations. See the signing caveat below before you generate.
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.

Prerequisites

For TypeScript

Node.js 18+. Uses openapi-typescript (types) + openapi-fetch (runtime). No Java, no code to vendor — types only.

For Python / Go / Java / others

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.

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

Generate the types

npx openapi-typescript \
  https://phosra-api-sandbox-production.up.railway.app/openapi.yaml \
  -o ./phosra.d.ts
Real output:
✨ 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):
phosra.d.ts (generated)
"/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"];
                };
            };
            // …
        };
    };
};
2

Make a typed call

npm install openapi-fetch
run.ts
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):
node --experimental-strip-types run.ts
Real output:
family: Emma's Family
age_group: preteen
rules_enabled: 20
Prefer a batteries-included, hand-maintained client? Skip generation and use the first-party @phosra/sdk (PhosraClient) — it wraps the same API with retries and token management.

Python — openapi-generator-cli

1

Generate the client

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, …).
2

Install and call the sandbox

python3 -m venv .venv && . .venv/bin/activate
pip install ./python-client
run_client.py
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)
python3 run_client.py
Real output:
family: Emma's Family
age_group: preteen
rules_enabled: 20

Go — openapi-generator-cli

1

Generate the client

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

Call the sandbox

main.go
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())
}
go mod tidy && go run .
Real output:
family: Emma's Family
age_group: preteen
rules_enabled: 20

Java and everything else

The same openapi-generator-cli produces clients for 60+ languages — swap the -g flag. Java, for example:
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:
const client = createClient<paths>({
  baseUrl: "https://phosra-api-sandbox-production.up.railway.app/api/v1",
  headers: { Authorization: `Bearer ${process.env.PHOSRA_API_KEY}` },
});

Get a sandbox key

Mint a phosra_test_… key on the Keys page. See Authentication for the full header rules (Authorization: Bearer is canonical; X-Api-Key is accepted as an equivalent).

The data-plane signing caveat

If you generate from openapi.data-plane.yaml, be aware that those endpoints are not plain REST:
A generated client gives you the correct wire shapes for the data plane, but it will not produce valid requests on its own. Profile GETs are RFC 9421-signed by the resolver, binding POSTs require an accredited caller signature, and profile responses are root-verifiable signed documents. Signing and verification are cryptographic steps the generator does not emit.
For anything on the data plane, use the maintained SDKs that implement the signing:
  • @openchildsafety/ocss — RFC 9421 sign/verify, sealed envelopes, trust-list verification.
  • @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:
# 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 ...
The spec is versioned by the /api/v1 path and evolves additively (see 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.

Next steps

Quickstart

Zero-to-enforcement against the open sandbox — no key needed.

TypeScript SDK

The hand-maintained PhosraClient if you’d rather not generate.

Authentication

Keys, headers, and the phosra_test_ vs phosra_live_ split.

API Reference

Every endpoint, field, and error — the same spec you just generated from.