Developer documentation

API reference

OpenAI-compatible — point your SDK at our base URL and keep your code. Add a header to pin data residency, declare PHI, or pick a model tier.

https://phi-cloud.com/api/v1Get started
Per-request residency headersPHI-aware routingDrop-in OpenAI SDK

Quickstart

From zero to a first call in under a minute.

Point your existing OpenAI SDK at https://phi-cloud.com/api/v1, pass your phi_live_ key, and add X-Region to pin where the request is processed. That is the whole integration.

POST/v1/chat/completions
curl https://phi-cloud.com/api/v1/chat/completions \  -H "Authorization: Bearer phi_live_…" \  -H "X-PHI: false" \  -H "X-Region: CH" \  -H "Content-Type: application/json" \  -d '{    "model": "auto",    "messages": [      {"role": "user", "content": "Hello"}    ]  }'

No code? Use the hosted chat

Prefer to talk to it directly? /dashboard/chat is the same router behind a multi-turn chat UI — pick a region, pick a model, send messages. Conversation history stays in your browser; the gateway stores nothing.

Heads up

Live keys are prefixed phi_live_. Keep them server-side — never ship a key to a browser or mobile client.

Auth

Authentication

Every request carries your secret API key as a bearer token in the Authorization header. Keys are stateless and verified without a database round-trip.

Authorization: Bearer phi_live_…
Authorizationstringrequired

Bearer token. Issue and rotate keys in the dashboard.

Routing

Request headers

Two optional request headers steer the router. Omit them to fall back to your account defaults. (The model tier hint is a request-body field, not a header — see Chat completions.)

X-PHItrue | falseoptional

Declare the payload class. Set true when the request contains protected health information — the router then restricts to PHI-eligible, in-jurisdiction providers. Defaults to false.

X-RegionCH | EU | US | UK | WORLDoptional

Override the routing region to pin where the request is processed. Defaults to WORLD.

Endpoint

Chat completions

POST/v1/chat/completionsStandard OpenAI chat schema. Set model to auto to let the router choose, or pin a specific model id from /v1/models.

modelstringrequired

Model id, or auto to let the router pick the cheapest eligible model for your region and tier.

messagesarrayrequired

The conversation, as OpenAI-style { role, content } objects.

temperaturenumberoptional

Sampling temperature. Passed through to the upstream model.

max_tokensnumberoptional

Maximum number of tokens to generate in the completion.

tierfast | baseline | thinking | code | qualityoptional

Body field (not a header) that biases auto routing toward a class of model — a soft preference the router honours when an eligible model in that tier exists, otherwise it falls back to the cheapest eligible model. Distinct from the descriptive quality_tier (low/medium/high) that /v1/models reports per model.

POST/v1/chat/completions
curl https://phi-cloud.com/api/v1/chat/completions \  -H "Authorization: Bearer phi_live_…" \  -H "X-PHI: false" \  -H "X-Region: CH" \  -H "Content-Type: application/json" \  -d '{    "model": "auto",    "messages": [      {"role": "system", "content": "You are a careful assistant."},      {"role": "user", "content": "Hello"}    ]  }'

Endpoint

Vision (images)

POST/v1/chat/completionsVision is not a separate endpoint — send a user message whose content is an array of parts, mixing text and image_url (an https or data: URI). The router biases to a vision-capable model. Available in CH and EU.

content[]arrayrequired

Parts of type text or image_url. A data URI must stay under 200 KB.

POST/v1/chat/completions
curl https://phi-cloud.com/api/v1/chat/completions \  -H "Authorization: Bearer phi_live_…" \  -H "X-Region: CH" \  -H "Content-Type: application/json" \  -d '{    "model": "auto",    "messages": [{      "role": "user",      "content": [        {"type": "text", "text": "What is in this image?"},        {"type": "image_url",         "image_url": {"url": "data:image/jpeg;base64,/9j/4AAQ…"}}      ]    }]  }'

Endpoint

Embeddings

POST/v1/embeddingsGenerate embedding vectors for one or more inputs. The same residency rules and X-PHI gate apply.

modelstringrequired

Embedding model id, or auto.

inputstring | string[]required

A single string or an array of strings to embed.

POST/v1/embeddings
curl https://phi-cloud.com/api/v1/embeddings \  -H "Authorization: Bearer phi_live_…" \  -H "X-PHI: false" \  -H "Content-Type: application/json" \  -d '{    "model": "auto",    "input": ["text to embed"]  }'

Endpoint

Speech-to-text

POST/v1/audio/transcriptionsOpenAI transcription shape — multipart/form-data with a file field. Available in CH, EU and US (residency-separate, no cross-border failover). Max 25 MB.

filebinaryrequired

The audio file (multipart field file).

modelstringoptional

auto, or pin whisper.

response_formatstringoptional

json (default), text, srt, vtt, or verbose_json.

POST/v1/audio/transcriptions
curl https://phi-cloud.com/api/v1/audio/transcriptions \  -H "Authorization: Bearer phi_live_…" \  -H "X-Region: EU" \  -F "file=@meeting.mp3" \  -F "model=auto"

Endpoint

Text-to-speech

POST/v1/audio/speechOpenAI speech shape — JSON in, binary audio out. Available in CH, EU and US. voice is optional — omit it and the regional host picks an appropriate neural voice.

inputstringrequired

The text to synthesize (max 4096 characters).

voicestringoptional

Provider voice id. Omit for a region-appropriate default.

response_formatstringoptional

mp3 (default), wav, opus, aac, flac, pcm.

POST/v1/audio/speech
curl https://phi-cloud.com/api/v1/audio/speech \  -H "Authorization: Bearer phi_live_…" \  -H "X-Region: EU" \  -H "Content-Type: application/json" \  -d '{    "model": "auto",    "input": "Hello from phi-cloud."  }' --output speech.mp3

Endpoint

Voice catalogue

GET/v1/audio/voicesWhich voices can actually serve this request. Same {object:"list", data:[…]} shape as /v1/models, scoped by X-Region and X-PHI — a PHI caller only sees voices on PHI-eligible hosts. Free and unbilled (auth is still required).

languagequery stringoptional

Filter across every provider. Matches a bare language or any locale under it — fr matches fr-CH and fr-FR. When set, each voice carries native: true|false and natives sort first: a multilingual voice whose own locale is de-DE can read French, but it will sound German.

GET/v1/audio/voices
curl "https://phi-cloud.com/api/v1/audio/voices?language=fr" \  -H "Authorization: Bearer phi_live_…" \  -H "X-Region: CH"

Partial results are normal

Each entry carries its provider, model and phi_eligible. If one upstream catalogue is unreachable it is reported in unavailable and the remaining providers still return — the endpoint never blanks on a single failure.

Endpoint

OCR

POST/v1/ocrDocument OCR. This is the one endpoint that is not OpenAI-shaped (OpenAI has no OCR equivalent) — it takes a Mistral-native document object and returns per-page markdown. Available in CH, EU and US.

documentobjectrequired

{ type: "document_url" | "image_url", url } an https or data: URI.

pagesnumber[]optional

Restrict OCR to specific page indices.

annotatebooleanoptional

Request structured annotations (billed at the higher annotation rate).

POST/v1/ocr
curl https://phi-cloud.com/api/v1/ocr \  -H "Authorization: Bearer phi_live_…" \  -H "X-Region: EU" \  -H "Content-Type: application/json" \  -d '{    "model": "auto",    "document": {"type": "document_url", "url": "https://…/report.pdf"}  }'

Endpoint

List models

GET/v1/modelsReturns the catalog visible to your account. The list is scoped to your X-Region / X-PHI — there is no per-entry region field; the catalog is filtered to the routes that would succeed for the region and data-class you request. Use it to render a model picker.

phi_eligibleboolean

true = the model may carry PHI on a DPA/BAA-verified host in that region (health data is OK). false = general traffic only (standard DPA, no health data).

quality_tierlow | medium | high

A coarse quality / capability band derived from the model class — most meaningful for chat / LLM models — letting a caller pick a tier. Distinct from the routing tier body field on /v1/chat/completions.

supports_toolsboolean

Whether the model accepts OpenAI function calling.

GET/v1/models
curl https://phi-cloud.com/api/v1/models \  -H "Authorization: Bearer phi_live_…" \  -H "X-Region: CH"

Residency

Response headers

Every 200 response echoes the routing decision so you can audit residency and cost per request.

x-phi-routedmodel/region/class

The resolved route: modelId/regionCode/dataClass — authoritative record of what served the request.

x-phi-tierphi | non_phi

Whether the chosen route was PHI-eligible.

x-phi-attemptsnumber

How many routes were tried before one succeeded (fail-over stays inside the PHI tier for PHI requests).

x-phi-cost-micronumber

Metered cost of the request, in USD micro-units (1 = $0.000001). The API always reports cost in USD micro; your wallet balance is shown in prepaid credits (1 USD = 300 credits).

x-request-iduuid

Unique id for the request — quote it in support tickets.

< HTTP/2 200< x-phi-routed: gemma-4/CH/general< x-phi-tier: non_phi< x-phi-attempts: 1< x-phi-cost-micro: 4200< x-request-id: 9f1c…

Routing

Models & routing

Routing is region-resident: set X-Region and the request goes to that region's resident provider. You can also pin a canonical model name (e.g. gemma-4, qwen3-embedding-8b) and the router serves it from whichever provider hosts it in your region. PHI requests are filtered to providers verified for that jurisdiction and never spill to an unverified host. See /network for the live region map and /vendors for the full provider & model registry.

resident providerper region

Each region routes to its resident host: CH → Infomaniak, EU → Scaleway, US → Together AI, and other regions → Google.

embeddingsCH / EU

Production embeddings run in CH (Infomaniak) and EU (Scaleway) — the same model, Qwen3-Embedding-8B (4096-d).US and other regions return no_route for embeddings until the staged Fireworks (US) / Azure / Bedrock (other regions) rows are enabled.

PHI tierX-PHI: true

Served only by providers whose data-processing agreement is verified for the region: CH → Infomaniak + Azure, EU → Scaleway + Azure, US → Azure (OCR / TTS / STT only). A region or modality with no verified host returns 403.

Compliance posture

Infomaniak and Scaleway operate under nFADP / GDPR (DPA); Azure additionally carries a HIPAA BAA. Other providers become PHI-eligible per-region as each agreement lands.

Want the full picture?

The routing guide walks through region residency, PHI gating, canonical aliases, failover, and which modalities are available where — in prose, with the coverage tables.

Endpoints

Math & ping

Two more endpoints round out the surface.

/v1/math/chat/completionsPOST

Identical to /v1/chat/completions — same auth, shape and routing — with a math-oriented system prompt and a code-execution sandbox enabled by default (override with code_execution: false). The model can run Python, R, or SQL in a region-pinned, network-isolated sandbox to compute and verify; charts come back as inspectable SVG (fenced ```svg blocks, never raster) and diagrams as ```mermaid. The response carries x-phi-sandbox / x-phi-sandbox-figures. General traffic only.

/v1/pingGET / POST

Free setup diagnostic: validates your key, dry-runs routing, and reports billing_active (true once you have prepaid credits; 1 USD = 300 credits). No upstream call, no usage — exempt from the payment gate so you can verify a key before adding credits.

POST/v1/math/chat/completions
# The math agent picks the tool for the job. Ask a# relational question and it runs SQL in the DuckDB sandbox.curl https://phi-cloud.com/api/v1/math/chat/completions \  -H "Authorization: Bearer phi_live_…" \  -H "X-Region: EU" \  -H "Content-Type: application/json" \  -d '{    "model": "qwen3.5",    "messages": [{      "role": "user",      "content": "Here is monthly revenue as CSV: month,usd\n2026-01,1200\n2026-02,1810\n2026-03,1540. Load it into DuckDB, compute the month-over-month growth rate, and return the fastest-growing month."    }]  }'# The agent writes SQL, runs it, and answers from the real result:#   CREATE TABLE rev AS SELECT * FROM read_csv_auto('/workspace/rev.csv');#   SELECT month, usd / lag(usd) OVER (ORDER BY month) - 1 AS mom FROM rev;# -> tables persist across tool calls, so it can build up and re-query.

Endpoints

Image & video generation

POST/v1/images/generations · /v1/videos/generationsText-to-image, text/image-to-video and audio-driven talking avatars. General (non-PHI) content only — an X-PHI: true request returns phi_blocked. Images settle synchronously; video is asynchronous — enqueue, then poll /v1/videos/{id} until status is completed.

modelstringoptional

krea-2 (image), wan or seedance (video), or avatar (talking avatar). Generation routes to fal.ai (paid, general / non-PHI only). On video you can pin the model or just pass quality.

qualitystringoptional

Video only — standard (default, Krea-Wan 14B, $0.088/sec) or premium (Seedance 2.0, up to 720p with native audio, $0.334/sec). The 202 response echoes price_micro_per_second so you know the rate before the job settles. Doesn’t apply to avatar mode.

promptstringrequired

The text prompt. For image-to-video or a talking avatar, also pass an image (and audio for the avatar).

durationintegeroptional

Premium video only — clip length in seconds (4–15, default 5). Also accepts resolution (480p | 720p) and aspect_ratio. Billing is per generated second, settled on the first completed poll.

POST/v1/images/generations
curl https://phi-cloud.com/api/v1/images/generations \  -H "Authorization: Bearer phi_live_…" \  -H "Content-Type: application/json" \  -d '{    "model": "krea-2",    "prompt": "a calm clinic waiting room, soft morning light"  }'
POST/v1/videos/generations
# 1 — enqueue (async): returns a job id + the per-second ratecurl https://phi-cloud.com/api/v1/videos/generations \  -H "Authorization: Bearer phi_live_…" \  -H "Content-Type: application/json" \  -d '{    "quality": "standard",    "prompt": "a slow drone shot over a green valley"  }'# → 202 {"id":"…","status":"queued","quality":"standard","price_micro_per_second":88000}# premium tier (Seedance 2.0) — same call, higher fidelity + native audiocurl https://phi-cloud.com/api/v1/videos/generations \  -H "Authorization: Bearer phi_live_…" \  -H "Content-Type: application/json" \  -d '{    "quality": "premium",    "prompt": "a slow drone shot over a green valley",    "duration": 8,    "aspect_ratio": "16:9"  }'# 2 — poll until status is completedcurl https://phi-cloud.com/api/v1/videos/JOB_ID \  -H "Authorization: Bearer phi_live_…"

Keep generated assets private

fal stores request I/O and serves public URLs by default; the adapter disables upstream retention. For confidential content, enable the optional R2 re-host — outputs are copied to our own bucket and served from short-lived signed /v1/media/{key} URLs (the HMAC URL is the capability; no auth header) instead of the public fal URL.

Endpoints

ETL & search

POST/v1/etl · /v1/etl/query · /v1/searchExtract, embed and store your sources into a searchable collection, query it semantically, and run live web or async deep-research search — a stateless white-label of Twin Browser. General (non-PHI) content only (an X-PHI: true request returns phi_blocked) and paid keys only.

/v1/etlPOST

Ingest sources (url, urls, html or text): the upstream extracts, chunks, embeds and stores them. Pass an optional collection — it is namespaced to your account server-side, so it can never collide with another customer’s.

/v1/etl/queryPOST

Semantic retrieval over your collection. query is required; returns the best-matching chunks with scores. Scoped to your namespace — a query can only reach your own content.

/v1/searchPOST

Live web search. query is required. depth: "deep" runs an asynchronous research pass and returns a customer-bound job token to poll at /v1/jobs/{token}; shallow search is synchronous.

POST/v1/etl · /v1/etl/query · /v1/search
# 1 — ingest sources into your (namespaced) collectioncurl https://phi-cloud.com/api/v1/etl \  -H "Authorization: Bearer phi_live_…" \  -H "Content-Type: application/json" \  -d '{ "sources": ["https://example.com/handbook"], "collection": "handbook" }'# 2 — semantic query over that collectioncurl https://phi-cloud.com/api/v1/etl/query \  -H "Authorization: Bearer phi_live_…" \  -H "Content-Type: application/json" \  -d '{ "query": "what is the refund window?", "collection": "handbook" }'# 3 — web search; depth:"deep" returns a job token to poll at /v1/jobs/{token}curl https://phi-cloud.com/api/v1/search \  -H "Authorization: Bearer phi_live_…" \  -H "Content-Type: application/json" \  -d '{ "query": "latest nFADP guidance", "depth": "deep" }'

Stateless & pass-through billed

phi-cloud stores nothing here — the vector store, collections and jobs all live in Twin Browser, isolated per customer. You pay exactly the upstream’s reported credits, converted at 1 USD = 1000 credits with no phi-cloud markup; async jobs settle once, on the first terminal poll.

Endpoints

Sandbox run

POST/v1/sandbox/runDeterministic, model-free code execution — run Python, R or SQL over your own data in a region-pinned, network-isolated sandbox and get a structured result back. No LLM in the loop (that is /v1/math/chat/completions). General traffic only (an X-PHI: true request returns phi_blocked until the sandbox BAA lands) and paid keys only.

languagestringrequired

python, r or sql (DuckDB).

codestringrequired

The source to execute. Returns a structured SandboxRunResult: ok, stdout, stderr, resultText, error (and any captured SVG artifacts).

inputJSON value

Optional data payload. Written to /workspace/input.json and, for Python, pre-bound as the variable phi_input. Read it in SQL with read_json_auto('/workspace/input.json').

timeout_msnumber

Optional per-run timeout (capped at 120000). Requires X-Region to be CH, EU, UK or US — other regions return no_sandbox_region.

POST/v1/sandbox/run
# Deterministic exec — no model in the loop. `input` is written to# /workspace/input.json and, for Python, pre-bound as `phi_input`.curl https://phi-cloud.com/api/v1/sandbox/run \  -H "Authorization: Bearer phi_live_…" \  -H "X-Region: EU" \  -H "Content-Type: application/json" \  -d '{    "language": "python",    "code": "import statistics; print(statistics.mean(r[\"usd\"] for r in phi_input))",    "input": [{ "month": "2026-01", "usd": 1200 }, { "month": "2026-02", "usd": 1810 }]  }'# -> { "ok": true, "stdout": "1505\n", "stderr": "", "resultText": "", "error": null }# SQL: read the same payload with read_json_auto('/workspace/input.json').

Billed on wall-clock seconds

Each run is metered on its wall-clock duration (rounded up, minimum one second) and carries the usual x-phi-cost-micro header, plus x-phi-sandbox-seconds and x-phi-sandbox (the placement boundary). One ephemeral container per request, torn down after — nothing persists.

Reference

Errors

Errors return a JSON body of the shape { "error": { "code", "message" } } with a matching HTTP status.

401missing_authorization

No Bearer token on the request.

401invalid_api_key

The token is invalid or revoked.

402payment_required

Out of credits. Top up your prepaid credit balance in the dashboard → Billing (or enable auto-recharge).

403phi_blocked

X-PHI: true but no PHI-verified route exists for the requested region and modality. This is correct behaviour — the gateway refuses to silently cross a border.

422no_route

No route serves this task / region / data-class combination.

400invalid_json

The request body was not valid JSON, or failed schema validation.

502upstream_error

Every candidate route failed at the upstream provider.

HTTP/2 403content-type: application/json{  "error": {    "code": "phi_blocked",    "message": "No PHI-verified route for region=US, modality=chat."  }}

403 phi_blocked is by design

When X-PHI: true is set in a region or modality with no verified provider, the gateway refuses the request rather than failing over to an unverified route. Pin an X-Region with a verified PHI host (e.g. CH or EU) for that modality.

Keep going

Next steps

Where to go from here once your first call is working.

/networkpage

Live region map and which providers are PHI-eligible where.

/compliancepage

nFADP / GDPR posture, sub-processors, and the audit trail you ship by default.

/pricingpage

Prepaid credits (1 USD = 300 credits; $20 / 6,000-credit minimum), per-token rates, and the flat +10% gateway margin.

/platformpage

Architecture, statelessness contract, and how routing decisions are made.