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 startedQuickstart
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.
/v1/chat/completionscurl 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_…AuthorizationstringrequiredBearer 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 | falseoptionalDeclare 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 | WORLDoptionalOverride the routing region to pin where the request is processed. Defaults to WORLD.
Endpoint
Chat completions
POST/v1/chat/completions — Standard OpenAI chat schema. Set model to auto to let the router choose, or pin a specific model id from /v1/models.
modelstringrequiredModel id, or auto to let the router pick the cheapest eligible model for your region and tier.
messagesarrayrequiredThe conversation, as OpenAI-style { role, content } objects.
temperaturenumberoptionalSampling temperature. Passed through to the upstream model.
max_tokensnumberoptionalMaximum number of tokens to generate in the completion.
tierfast | baseline | thinking | code | qualityoptionalBody 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.
/v1/chat/completionscurl 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/completions — Vision 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[]arrayrequiredParts of type text or image_url. A data URI must stay under 200 KB.
/v1/chat/completionscurl 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/embeddings — Generate embedding vectors for one or more inputs. The same residency rules and X-PHI gate apply.
modelstringrequiredEmbedding model id, or auto.
inputstring | string[]requiredA single string or an array of strings to embed.
/v1/embeddingscurl 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/transcriptions — OpenAI transcription shape — multipart/form-data with a file field. Available in CH, EU and US (residency-separate, no cross-border failover). Max 25 MB.
filebinaryrequiredThe audio file (multipart field file).
modelstringoptionalauto, or pin whisper.
response_formatstringoptionaljson (default), text, srt, vtt, or verbose_json.
/v1/audio/transcriptionscurl 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/speech — OpenAI 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.
inputstringrequiredThe text to synthesize (max 4096 characters).
voicestringoptionalProvider voice id. Omit for a region-appropriate default.
response_formatstringoptionalmp3 (default), wav, opus, aac, flac, pcm.
/v1/audio/speechcurl 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.mp3Endpoint
Voice catalogue
GET/v1/audio/voices — Which 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 stringoptionalFilter 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.
/v1/audio/voicescurl "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/ocr — Document 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[]optionalRestrict OCR to specific page indices.
annotatebooleanoptionalRequest structured annotations (billed at the higher annotation rate).
/v1/ocrcurl 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/models — Returns 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_eligiblebooleantrue = 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 | highA 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_toolsbooleanWhether the model accepts OpenAI function calling.
/v1/modelscurl 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/classThe resolved route: modelId/regionCode/dataClass — authoritative record of what served the request.
x-phi-tierphi | non_phiWhether the chosen route was PHI-eligible.
x-phi-attemptsnumberHow many routes were tried before one succeeded (fail-over stays inside the PHI tier for PHI requests).
x-phi-cost-micronumberMetered 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-iduuidUnique 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 regionEach region routes to its resident host: CH → Infomaniak, EU → Scaleway, US → Together AI, and other regions → Google.
embeddingsCH / EUProduction 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: trueServed 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/completionsPOSTIdentical 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 / POSTFree 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.
/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/generations — Text-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.
modelstringoptionalkrea-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.
qualitystringoptionalVideo 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.
promptstringrequiredThe text prompt. For image-to-video or a talking avatar, also pass an image (and audio for the avatar).
durationintegeroptionalPremium 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.
/v1/images/generationscurl 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" }'/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/search — Extract, 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/etlPOSTIngest 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/queryPOSTSemantic 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/searchPOSTLive 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.
/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/run — Deterministic, 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.
languagestringrequiredpython, r or sql (DuckDB).
codestringrequiredThe source to execute. Returns a structured SandboxRunResult: ok, stdout, stderr, resultText, error (and any captured SVG artifacts).
inputJSON valueOptional 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_msnumberOptional per-run timeout (capped at 120000). Requires X-Region to be CH, EU, UK or US — other regions return no_sandbox_region.
/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_authorizationNo Bearer token on the request.
401invalid_api_keyThe token is invalid or revoked.
402payment_requiredOut of credits. Top up your prepaid credit balance in the dashboard → Billing (or enable auto-recharge).
403phi_blockedX-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_routeNo route serves this task / region / data-class combination.
400invalid_jsonThe request body was not valid JSON, or failed schema validation.
502upstream_errorEvery 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.
/networkpageLive region map and which providers are PHI-eligible where.
/compliancepagenFADP / GDPR posture, sub-processors, and the audit trail you ship by default.
/pricingpagePrepaid credits (1 USD = 300 credits; $20 / 6,000-credit minimum), per-token rates, and the flat +10% gateway margin.
/platformpageArchitecture, statelessness contract, and how routing decisions are made.