{"openapi":"3.1.0","info":{"title":"Straits Hub — Enterprise AI Fabric Gateway","version":"1.0.0","description":"One governed interface between every employee, application and agent — and every AI resource the company is authorized to use. OpenAI/OpenRouter-compatible chat, OpenAI Responses and Anthropic Messages protocol skins, plus embeddings, rerank, moderations, audio, realtime session descriptors, images, async video and batch jobs, files/artifacts, model discovery, a full generation audit ledger and generation feedback.\n\nEvery generation runs the fabric pipeline: guardrails → exact cache → two-stage routing (hard filters, then a dynamic latency/cost/quality/quota objective) → provider dispatch on trusted egress nodes with error-conditioned fallback → output guardrails → audit. Fabric behavior is documented under `x-fabric-*` extensions.","contact":{"name":"Straits Hub Platform Team"}},"servers":[{"url":"/v1","description":"Canonical prefix"},{"url":"/api/v1","description":"Alias prefix (same handlers, memo §4.1)"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Chat","description":"OpenAI/OpenRouter-compatible chat completions."},{"name":"Responses","description":"OpenAI Responses protocol skin."},{"name":"Messages","description":"Anthropic Messages protocol skin."},{"name":"Embeddings","description":"Pinned-model embeddings — never a silent vector-space change."},{"name":"Rerank","description":"Query/document relevance scoring."},{"name":"Moderations","description":"Policy classification driven by the fabric's own guardrail evaluators."},{"name":"Audio","description":"Speech synthesis and transcription."},{"name":"Realtime","description":"Realtime session descriptors — routed once, pinned for the session."},{"name":"Images","description":"Synchronous image generation."},{"name":"Video","description":"Asynchronous video jobs with polling and cancellation."},{"name":"Batch","description":"Durable asynchronous batch processing."},{"name":"Files & Artifacts","description":"Metadata-only registration; bytes go direct to storage."},{"name":"Models","description":"Canonical models and logical service profiles."},{"name":"Generations","description":"Usage, attempts and route-explanation audit surface."},{"name":"Feedback","description":"Runtime quality signal on ledgered generations."},{"name":"Meta","description":"API description."}],"paths":{"/chat/completions":{"post":{"operationId":"createChatCompletion","summary":"Create a chat completion","tags":["Chat"],"description":"OpenAI/OpenRouter-compatible chat endpoint. Accepts canonical model ids, aliases, logical profiles (`@company/…`, `fabric/auto`) and the OpenRouter `models` fallback array. Every request runs the full fabric pipeline: guardrails (PRE_ROUTE/PRE_MODEL) → exact-cache lookup → two-stage routing → quota reservation → provider dispatch with error-conditioned fallback → output guardrails (POST_MODEL/PRE_RETURN) → cache store → audit ledger.\n\nSet `stream: true` for SSE: `data: {chat.completion.chunk}` frames paced like provider tokens, a final usage-bearing chunk, then `data: [DONE]`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"},"example":{"model":"@company/general-balanced","session_id":"agent-session-01HXYZ","messages":[{"role":"user","content":"Summarize our Q3 supply posture in 3 bullets."}],"routing":{"deadline_ms":15000,"maximum_cost_usd":0.2,"explain":true}}}}},"responses":{"200":{"description":"Completion (JSON) or SSE stream when `stream: true`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionResponse"}},"text/event-stream":{"schema":{"$ref":"#/components/schemas/ChatCompletionChunk"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget ceiling reached (`budget_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Guardrail block (`content_policy_rejection`, `dlp_block`). Never retried on a more permissive route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exhausted (`rate_limited`, `quota_exhausted`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Provider-plane failure after fallback exhaustion (`provider_unavailable`, `network_timeout`, `egress_unavailable`, `internal`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"chat","default_profile":"principal default profile","cache_eligible":true,"streaming":true,"notes":"Session-sticky model pinning via `session_id`; OpenRouter `provider.zdr` and `provider.only` are hard route filters."},"x-fabric-metadata":"Attach `fabric_metadata` via `routing.explain: true`, header `X-Fabric-Explain: true`, or `X-OpenRouter-Metadata: enabled` (metadata without unmasking node refs)."}},"/responses":{"post":{"operationId":"createResponse","summary":"Create a response (OpenAI Responses skin)","tags":["Responses"],"description":"OpenAI Responses-compatible surface over the same pipeline. Requires one of `input`, `instructions`, `prompt` or `messages`. Streaming emits typed `response.*` events (`response.created`, `response.output_item.added`, `response.content_part.added`, `response.output_text.delta`, …, `response.completed`) with monotonic `sequence_number`s and no `[DONE]` terminator.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponsesRequest"},"example":{"model":"@company/general-fast","input":"Draft a two-line status update about the fabric rollout.","stream":false}}}},"responses":{"200":{"description":"Response object (JSON) or typed `response.*` SSE events when `stream: true`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseObject"}},"text/event-stream":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"Event type, mirrors the SSE `event:` name."},"sequence_number":{"type":"integer"}},"additionalProperties":true}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget ceiling reached (`budget_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Guardrail block (`content_policy_rejection`, `dlp_block`). Never retried on a more permissive route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exhausted (`rate_limited`, `quota_exhausted`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Provider-plane failure after fallback exhaustion (`provider_unavailable`, `network_timeout`, `egress_unavailable`, `internal`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"responses","cache_eligible":true,"streaming":true},"x-fabric-metadata":"Same opt-ins as /chat/completions; `fabric_metadata` rides on the completed response object."}},"/messages":{"post":{"operationId":"createMessage","summary":"Create a message (Anthropic skin)","tags":["Messages"],"description":"Anthropic Messages-compatible surface: content blocks, `stop_reason`, Anthropic usage keys, and Anthropic named-event streaming (`message_start`, `ping`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta`, `message_stop` — no `[DONE]`). Tool calls surface as `tool_use` content blocks with `input_json_delta` streaming. Errors use the Anthropic envelope `{ type: \"error\", error: { type, message } }`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnthropicMessagesRequest"},"example":{"model":"anthropic/claude-sonnet","max_tokens":512,"messages":[{"role":"user","content":"Review this contract clause for risk."}]}}}},"responses":{"200":{"description":"Anthropic message (JSON) or named-event SSE stream when `stream: true`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnthropicMessageResponse"}},"text/event-stream":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"Event payload type (matches the SSE `event:` name)."}},"additionalProperties":true}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnthropicError"}}}},"401":{"description":"Authentication failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnthropicError"}}}},"403":{"description":"Guardrail block.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnthropicError"}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnthropicError"}}}},"5XX":{"description":"Provider-plane failure.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnthropicError"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"messages","cache_eligible":true,"streaming":true},"x-fabric-metadata":"Same opt-ins; `fabric_metadata` rides on the non-streaming message object."}},"/embeddings":{"post":{"operationId":"createEmbeddings","summary":"Create embeddings","tags":["Embeddings"],"description":"OpenAI-compatible embeddings. `model` is REQUIRED and must be an approved embedding model or a single-model embeddings profile — the fabric never falls back across embedding models or dimensions (a corpus embedded under one vector space is useless under another, memo §13.4). The gateway hard-fails rather than return vectors from a different model. Deterministic and aggressively exact-cached.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingsRequest"},"example":{"model":"openai/text-embedding-4","input":["fabric routing","quota shadow pricing"]}}}},"responses":{"200":{"description":"Embedding vectors.","headers":{"x-fabric-generation-id":{"description":"Ledger id of the generation that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingsResponse"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget ceiling reached (`budget_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Guardrail block (`content_policy_rejection`, `dlp_block`). Never retried on a more permissive route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exhausted (`rate_limited`, `quota_exhausted`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Provider-plane failure after fallback exhaustion (`provider_unavailable`, `network_timeout`, `egress_unavailable`, `internal`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"embeddings","default_profile":"@company/embeddings","cache_eligible":true,"no_model_fallback":true},"x-fabric-metadata":"Opt in via `routing.explain` / headers; response also carries `x-fabric-generation-id`."}},"/rerank":{"post":{"operationId":"createRerank","summary":"Rerank documents","tags":["Rerank"],"description":"Query/document relevance reranking (Cohere/Jina wire shape: `results: [{ index, relevance_score }]`). Defaults to the `@company/embeddings` profile when no model is named. Supports `top_n` truncation and `return_documents` echo.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RerankRequest"},"example":{"query":"quota shadow pricing","documents":["Routing objectives","Quota shadow prices bias the router away from scarce pools","Cache keys"],"top_n":2,"return_documents":true}}}},"responses":{"200":{"description":"Ranked results.","headers":{"x-fabric-generation-id":{"description":"Ledger id of the generation that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RerankResponse"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget ceiling reached (`budget_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Guardrail block (`content_policy_rejection`, `dlp_block`). Never retried on a more permissive route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exhausted (`rate_limited`, `quota_exhausted`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Provider-plane failure after fallback exhaustion (`provider_unavailable`, `network_timeout`, `egress_unavailable`, `internal`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"rerank","default_profile":"@company/embeddings","cache_eligible":true}}},"/moderations":{"post":{"operationId":"createModeration","summary":"Classify text for policy violations","tags":["Moderations"],"description":"OpenAI-compatible moderation wire shape, served by the fabric's own deterministic guardrail evaluators (`secrets-scanner`, `pii-redactor`, `pattern-dlp`, `prompt-injection-heuristic`, `toxicity-lite`) rather than a provider call — so no content leaves the fabric to classify it. Alongside the standard OpenAI omni categories, fabric DLP findings surface as extension categories `fabric/secrets`, `fabric/pii`, `fabric/dlp` and `fabric/prompt-injection`.\n\nEvery call is ledgered as a generation (`operation: \"moderation\"`, `cache_state: bypass`) with the underlying guardrail decisions attached, so moderation verdicts are searchable in the same audit plane as everything else (memo §14.1). The generation id is returned in `x-fabric-generation-id`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationsRequest"},"example":{"input":["Ship the release notes to the customer list.","here is my key AKIAIOSFODNN7EXAMPLE"]}}}},"responses":{"200":{"description":"Per-item moderation results.","headers":{"x-fabric-generation-id":{"description":"Ledger id of the generation that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationsResponse"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":false,"operation":"moderation","cache_eligible":false,"notes":"No provider dispatch and no routing: guardrail evaluators run locally and the call is recorded on the ledger for audit."}}},"/audio/speech":{"post":{"operationId":"createSpeech","summary":"Synthesize speech","tags":["Audio"],"description":"OpenAI-compatible text-to-speech. Returns raw `audio/mpeg` bytes (simulated deterministically by the provider plane). Fabric metadata travels in response headers since the body is binary: `x-fabric-generation-id`, `x-fabric-model`, and `x-fabric-metadata` (JSON) when metadata is requested. Defaults to `@company/voice`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeechRequest"},"example":{"model":"@company/voice","input":"Welcome to the Straits Hub fabric.","voice":"alloy"}}}},"responses":{"200":{"description":"MP3 audio bytes.","headers":{"x-fabric-generation-id":{"description":"Ledger id of the generation that produced this response.","schema":{"type":"string"}},"x-fabric-model":{"description":"Resolved canonical model.","schema":{"type":"string"}},"x-fabric-metadata":{"description":"JSON-encoded `FabricMetadata`, present when metadata was requested.","schema":{"type":"string"}}},"content":{"audio/mpeg":{"schema":{"type":"string","contentEncoding":"binary","contentMediaType":"audio/mpeg"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget ceiling reached (`budget_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Guardrail block (`content_policy_rejection`, `dlp_block`). Never retried on a more permissive route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exhausted (`rate_limited`, `quota_exhausted`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Provider-plane failure after fallback exhaustion (`provider_unavailable`, `network_timeout`, `egress_unavailable`, `internal`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"speech","default_profile":"@company/voice"}}},"/audio/transcriptions":{"post":{"operationId":"createTranscription","summary":"Transcribe audio","tags":["Audio"],"description":"OpenAI-compatible speech-to-text. Accepts `multipart/form-data` (SDK style — the `file` part's bytes are not parsed; metadata is kept for audit) or a plain JSON body. Returns `{ text, model }`. Defaults to `@company/voice`.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","contentEncoding":"binary","description":"Audio file (metadata recorded; content simulated)."},"model":{"type":"string"},"language":{"type":"string"}}}},"application/json":{"schema":{"type":"object","properties":{"model":{"type":"string"},"language":{"type":"string"},"file":{"type":"object","properties":{"filename":{"type":"string"},"size_bytes":{"type":"integer"},"content_type":{"type":"string"}}}},"additionalProperties":true},"example":{"model":"@company/voice","language":"en"}}}},"responses":{"200":{"description":"Transcript.","headers":{"x-fabric-generation-id":{"description":"Ledger id of the generation that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscriptionResponse"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget ceiling reached (`budget_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Guardrail block (`content_policy_rejection`, `dlp_block`). Never retried on a more permissive route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exhausted (`rate_limited`, `quota_exhausted`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Provider-plane failure after fallback exhaustion (`provider_unavailable`, `network_timeout`, `egress_unavailable`, `internal`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"transcription","default_profile":"@company/voice"}}},"/audio/translations":{"post":{"operationId":"createTranslation","summary":"Translate audio to English","tags":["Audio"],"description":"The sibling of `/audio/transcriptions` (memo §4.2 pairs them): same `multipart/form-data` or JSON intake, but the output language is always English. An inbound `language` names the **source** audio and is not echoed back — the response always reports `language: \"english\"`.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","contentEncoding":"binary","description":"Audio file (metadata recorded; content simulated)."},"model":{"type":"string"},"language":{"type":"string"}}}},"application/json":{"schema":{"type":"object","properties":{"model":{"type":"string"},"language":{"type":"string"},"file":{"type":"object","properties":{"filename":{"type":"string"},"size_bytes":{"type":"integer"},"content_type":{"type":"string"}}}},"additionalProperties":true},"example":{"model":"@company/voice","language":"ms"}}}},"responses":{"200":{"description":"English transcript.","headers":{"x-fabric-generation-id":{"description":"Ledger id of the generation that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranscriptionResponse"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget ceiling reached (`budget_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Guardrail block (`content_policy_rejection`, `dlp_block`). Never retried on a more permissive route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exhausted (`rate_limited`, `quota_exhausted`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Provider-plane failure after fallback exhaustion (`provider_unavailable`, `network_timeout`, `egress_unavailable`, `internal`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"transcription","default_profile":"@company/voice"}}},"/realtime/sessions":{"post":{"operationId":"createRealtimeSession","summary":"Create a realtime session descriptor","tags":["Realtime"],"description":"Realtime is routed **at session creation** (memo §13.1): the fabric plans the placement — model endpoint, account pool, region and egress node — once, and the session stays pinned to it for its lifetime, because mid-session provider fallback is not meaningful for a stateful audio socket. The chosen placement is returned under `fabric_metadata.placement` (node refs masked unless explain is requested); if routing cannot resolve a placement right now the descriptor is still issued with `placement: null` and a deferred note.\n\nThis core issues the session descriptor and an ephemeral OpenAI-style `client_secret` only — **no WebRTC/WebSocket transport is opened**.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RealtimeSessionRequest"},"example":{"model":"@company/voice","voice":"alloy","modalities":["audio","text"]}}}},"responses":{"201":{"description":"Session descriptor with ephemeral client secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RealtimeSession"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":false,"operation":"speech","default_profile":"@company/voice","streaming":false,"notes":"Routing runs once at session creation; the session pins to that placement for its lifetime."}}},"/images":{"post":{"operationId":"createImage","summary":"Generate images","tags":["Images"],"description":"OpenAI-compatible synchronous image generation. The simulated provider plane renders a deterministic 1024×1024 SVG delivered as a data URL (`response_format: url`) or base64 (`b64_json`). `n` is clamped to 1..4. Defaults to `@company/image`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImagesRequest"},"example":{"prompt":"Isometric illustration of a governed AI gateway","n":1,"response_format":"url"}}}},"responses":{"200":{"description":"Generated images.","headers":{"x-fabric-generation-id":{"description":"Ledger id of the generation that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImagesResponse"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget ceiling reached (`budget_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Guardrail block (`content_policy_rejection`, `dlp_block`). Never retried on a more permissive route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exhausted (`rate_limited`, `quota_exhausted`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Provider-plane failure after fallback exhaustion (`provider_unavailable`, `network_timeout`, `egress_unavailable`, `internal`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"image","default_profile":"@company/image"}}},"/images/edits":{"post":{"operationId":"createImageEdit","summary":"Edit an image","tags":["Images"],"description":"OpenAI-compatible image editing (memo §4.2). An edit differs from generation in what it carries, not how it routes: a source `image`, an optional `mask`, and a `prompt` describing the change. Both reference assets are recorded as metadata on the generation so the ledger shows what an edit derived from (memo §13.4). `image` is required — an edit without a source is a generation, and is refused rather than silently treated as one. Accepts `multipart/form-data` or JSON.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"image":{"type":"string","contentEncoding":"binary","description":"Source image (metadata recorded; content simulated)."},"mask":{"type":"string","contentEncoding":"binary"},"prompt":{"type":"string"},"model":{"type":"string"},"n":{"type":"integer"},"response_format":{"type":"string"}}}},"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string"},"image":{"type":"object","properties":{"filename":{"type":"string"},"size_bytes":{"type":"integer"},"content_type":{"type":"string"}},"additionalProperties":true},"mask":{"type":"object","properties":{"filename":{"type":"string"}},"additionalProperties":true},"model":{"type":"string"},"n":{"type":"integer"},"response_format":{"type":"string"}},"additionalProperties":true},"example":{"prompt":"make the sky dramatic","image":{"filename":"harbour.png","size_bytes":90210},"n":1,"response_format":"url"}}}},"responses":{"200":{"description":"Edited images.","headers":{"x-fabric-generation-id":{"description":"Ledger id of the generation that produced this response.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImagesResponse"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget ceiling reached (`budget_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Guardrail block (`content_policy_rejection`, `dlp_block`). Never retried on a more permissive route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exhausted (`rate_limited`, `quota_exhausted`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Provider-plane failure after fallback exhaustion (`provider_unavailable`, `network_timeout`, `egress_unavailable`, `internal`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"image","default_profile":"@company/image"}}},"/videos":{"post":{"operationId":"createVideo","summary":"Submit a video generation job","tags":["Video"],"description":"Asynchronous video generation (OpenRouter-style async contract). Returns **202** with `{ id, status, polling_url }`; poll `GET /videos/{id}` — jobs auto-progress on every read (queued → routing → submitted → running → succeeded, ~45 s simulated wall time). Cost is reserved at submit and settled on completion. Defaults to `@company/video`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoCreateRequest"},"example":{"model":"@company/video","prompt":"A cargo ship crossing the Straits at dawn","duration_seconds":8}}}},"responses":{"202":{"description":"Job accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoJob"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget ceiling reached (`budget_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Guardrail block (`content_policy_rejection`, `dlp_block`). Never retried on a more permissive route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exhausted (`rate_limited`, `quota_exhausted`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Provider-plane failure after fallback exhaustion (`provider_unavailable`, `network_timeout`, `egress_unavailable`, `internal`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"video","default_profile":"@company/video","notes":"Job-backed: routing happens at submit, execution progresses asynchronously."}},"get":{"operationId":"listVideos","summary":"List video jobs","tags":["Video"],"description":"Lists all video jobs newest-first, auto-progressing each on read.","responses":{"200":{"description":"Video job list.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list","type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/VideoJob"}}},"required":["object","data"]}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/videos/{id}":{"get":{"operationId":"retrieveVideo","summary":"Poll a video job","tags":["Video"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Job id (`job_…`).","example":"job_01h9"}],"description":"Polls one job (auto-progressing it). On success the job carries `output.artifacts` — an SVG poster frame (inline data URL) plus simulated MP4 metadata — and `cost_usd`.","responses":{"200":{"description":"Current job state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoJob"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such video job.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"cancelVideo","summary":"Cancel a video job","tags":["Video"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Job id (`job_…`)."}],"description":"Cancels a non-terminal job and releases its held cost reservation.","responses":{"200":{"description":"Cancelled job.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoJob"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such video job.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/batches":{"post":{"operationId":"createBatch","summary":"Create a batch job","tags":["Batch"],"description":"Durable asynchronous processing: submit up to 20 chat-like request objects. Returns **202**; items execute lazily through the full generation pipeline when the batch's execution window is reached (poll `GET /batches/{id}` to trigger and read per-item results).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchCreateRequest"},"example":{"requests":[{"custom_id":"a","model":"@company/general-fast","messages":[{"role":"user","content":"One-line summary of ZDR."}]},{"custom_id":"b","model":"@company/general-fast","messages":[{"role":"user","content":"One-line summary of quota shadow pricing."}]}]}}}},"responses":{"202":{"description":"Batch accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchJob"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget ceiling reached (`budget_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Guardrail block (`content_policy_rejection`, `dlp_block`). Never retried on a more permissive route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or quota exhausted (`rate_limited`, `quota_exhausted`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Provider-plane failure after fallback exhaustion (`provider_unavailable`, `network_timeout`, `egress_unavailable`, `internal`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":true,"operation":"batch","notes":"Each item routes independently at execution time."}},"get":{"operationId":"listBatches","summary":"List batch jobs","tags":["Batch"],"responses":{"200":{"description":"Batch list.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list","type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/BatchJob"}}},"required":["object","data"]}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/batches/{id}":{"get":{"operationId":"retrieveBatch","summary":"Poll a batch job","tags":["Batch"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Job id (`job_…`)."}],"description":"Reaching the execution window triggers the lazy run of every item through `runGeneration`; the response then carries per-item `results`.","responses":{"200":{"description":"Current batch state with per-item results when executed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchJob"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such batch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"cancelBatch","summary":"Cancel a batch job","tags":["Batch"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Job id (`job_…`)."}],"responses":{"200":{"description":"Cancelled batch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchJob"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such batch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/files":{"post":{"operationId":"registerFile","summary":"Register a file (metadata)","tags":["Files & Artifacts"],"description":"Registers file *metadata* — no bytes transit the gateway (memo §13.2: production clients upload directly to R2 via a presigned URL). Records name, MIME type, size, hash, data classification and retention. Returns **201** with the OpenAI-compatible file object.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileRegisterRequest"},"example":{"filename":"contracts-q3.pdf","mime_type":"application/pdf","size_bytes":482133,"classification":"confidential","retention_days":90}}}},"responses":{"201":{"description":"Registered file.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileObject"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listFiles","summary":"List files","tags":["Files & Artifacts"],"responses":{"200":{"description":"File list (newest first).","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list","type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FileObject"}}},"required":["object","data"]}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/files/{id}":{"get":{"operationId":"retrieveFile","summary":"Retrieve a file","tags":["Files & Artifacts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"File id (`file_…`)."}],"responses":{"200":{"description":"File metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileObject"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such file.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/artifacts":{"post":{"operationId":"registerArtifact","summary":"Register an artifact (metadata)","tags":["Files & Artifacts"],"description":"Registers artifact metadata (name + MIME type required), optionally linked to the producing job or generation. Returns **201** with the fabric artifact record.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArtifactRegisterRequest"},"example":{"name":"render-poster.svg","mime_type":"image/svg+xml","size_bytes":20480,"job_id":"job_01h9"}}}},"responses":{"201":{"description":"Registered artifact.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Artifact"}}}},"400":{"description":"Invalid request (`invalid_request`, `unsupported_parameter`, `context_too_long`, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listArtifacts","summary":"List artifacts","tags":["Files & Artifacts"],"description":"All artifacts newest-first: job outputs (video posters, simulated media) plus registered files.","responses":{"200":{"description":"Artifact list.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list","type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Artifact"}}},"required":["object","data"]}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/artifacts/{id}":{"get":{"operationId":"retrieveArtifact","summary":"Retrieve an artifact","tags":["Files & Artifacts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Artifact id (`art_…` or `file_…`)."}],"description":"Artifact detail including the inline `data_url` for small simulated artifacts such as video poster frames.","responses":{"200":{"description":"Artifact record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Artifact"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such artifact.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/models":{"get":{"operationId":"listModels","summary":"List models and profiles","tags":["Models"],"description":"OpenAI-shaped model list covering every canonical model (with fabric capability, lifecycle and per-provider pricing fields) plus the logical service profiles (`type: \"profile\"` entries carrying a `fabric_profile` object). Applications should target profiles, not volatile provider model names (memo §4.3).","responses":{"200":{"description":"Model + profile list.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list","type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Model"}}},"required":["object","data"]}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/models/{id}":{"get":{"operationId":"retrieveModel","summary":"Retrieve a model or profile","tags":["Models"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Canonical id, alias, or profile id. Slashes need no encoding (`/models/anthropic/claude-sonnet`, `/models/@company/general-fast`).","example":"anthropic/claude-sonnet"}],"responses":{"200":{"description":"Model or profile entry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Model not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/generations":{"get":{"operationId":"listGenerations","summary":"List generations","tags":["Generations"],"description":"Filtered list over the generation ledger, newest first. Compact records — fetch a single id for the full attempts / guardrail / route-explanation detail.","parameters":[{"name":"principal","in":"query","schema":{"type":"string"},"description":"Filter by principal id."},{"name":"model","in":"query","schema":{"type":"string"},"description":"Filter by resolved model."},{"name":"provider","in":"query","schema":{"type":"string"},"description":"Filter by winning provider."},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","running","succeeded","failed","blocked","cancelled"]}},{"name":"error_class","in":"query","schema":{"$ref":"#/components/schemas/ErrorClass"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500},"description":"Max records (capped at 500)."}],"responses":{"200":{"description":"Generation list.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list","type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Generation"}},"count":{"type":"integer"}},"required":["object","data","count"]}}}},"400":{"description":"Invalid enum value in a filter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/generations/{id}":{"get":{"operationId":"retrieveGeneration","summary":"Retrieve a generation (full audit record)","tags":["Generations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Generation id (`gen_…`).","example":"gen_01hb"}],"description":"The full audit record: usage + cost, every attempt in the fallback tree, guardrail decisions, the audit-ledger timeline, and the route explanation (plan scores + hard-filter rejections) when the request reached routing (memo §14.4).","responses":{"200":{"description":"Full generation record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationDetail"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Generation not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/feedback":{"post":{"operationId":"createFeedback","summary":"Rate a generation","tags":["Feedback"],"description":"Attach a user rating (and optional comment) to a ledgered generation. Feedback is the runtime evidence signal of the evaluation plane (memo §7.6): it feeds the console's feedback feed alongside offline scorecards, and quality signals only ever change routing through an applied router rollout — never directly from a single rating. Unknown `generation_id` returns **404** with `invalid_request`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackRequest"},"example":{"generation_id":"gen_01hb","rating":1,"comment":"Correct and well-scoped."}}}},"responses":{"201":{"description":"Stored feedback record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Feedback"}}}},"400":{"description":"Missing `generation_id`, `rating` not in {-1, 1}, or comment over 2000 characters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key (`authentication_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such generation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-fabric-routing":{"pipeline":false,"cache_eligible":false,"notes":"Control-plane write; no model is invoked."}}},"/openapi.json":{"get":{"operationId":"getOpenApi","summary":"This document","tags":["Meta"],"security":[],"description":"The gateway's OpenAPI 3.1 description. Unauthenticated. Rendered interactively at `/docs`.","responses":{"200":{"description":"OpenAPI 3.1 document.","content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"fab_…","description":"Fabric API key: `Authorization: Bearer fab_…` (an `x-api-key` header is also accepted). Demo keys: `fab_demo_admin` (admin), `fab_demo_app` (product app), `fab_demo_agent` (autonomous agent). Each key maps to a principal with a project, default logical profile, budgets and guardrail policy."}},"schemas":{"ErrorClass":{"type":"string","description":"Canonical fabric error class (memo §9.1). Stable across providers; carried in `error.code`.","enum":["authentication_failed","credential_expired","rate_limited","quota_exhausted","egress_unavailable","provider_overloaded","provider_unavailable","network_timeout","unsupported_parameter","unsupported_modality","context_too_long","invalid_structured_output","content_policy_rejection","dlp_block","tool_execution_failed","invalid_request","budget_exceeded","internal"]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable message."},"type":{"type":"string","description":"OpenAI-compatible error type (e.g. `invalid_request_error`, `rate_limit_error`)."},"code":{"$ref":"#/components/schemas/ErrorClass"},"param":{"type":["string","null"],"description":"Offending request parameter, when known."}},"required":["message","type","code","param"]}},"required":["error"],"description":"OpenAI wire error envelope. All non-Anthropic endpoints use this shape."},"AnthropicError":{"type":"object","properties":{"type":{"const":"error","type":"string"},"error":{"type":"object","properties":{"type":{"type":"string","description":"Anthropic error type (`invalid_request_error`, `authentication_error`, `rate_limit_error`, `overloaded_error`, …)."},"message":{"type":"string"}},"required":["type","message"]}},"required":["type","error"],"description":"Anthropic wire error envelope, used only by `POST /messages`."},"Usage":{"type":"object","properties":{"prompt_tokens":{"type":"integer"},"completion_tokens":{"type":"integer"},"total_tokens":{"type":"integer"},"prompt_tokens_details":{"type":"object","properties":{"cached_tokens":{"type":"integer","description":"Prompt tokens served from provider prompt cache."}},"required":["cached_tokens"]}},"required":["prompt_tokens","completion_tokens","total_tokens","prompt_tokens_details"],"description":"OpenAI chat-style usage."},"LedgerUsage":{"type":"object","properties":{"prompt_tokens":{"type":"integer"},"completion_tokens":{"type":"integer"},"cached_tokens":{"type":"integer"},"total_tokens":{"type":"integer"}},"required":["prompt_tokens","completion_tokens","cached_tokens","total_tokens"],"description":"Flat usage shape used by the ledger, rerank and image responses."},"ResponsesUsage":{"type":"object","properties":{"input_tokens":{"type":"integer"},"input_tokens_details":{"type":"object","properties":{"cached_tokens":{"type":"integer"}},"required":["cached_tokens"]},"output_tokens":{"type":"integer"},"output_tokens_details":{"type":"object","properties":{"reasoning_tokens":{"type":"integer"}},"required":["reasoning_tokens"]},"total_tokens":{"type":"integer"}},"required":["input_tokens","input_tokens_details","output_tokens","output_tokens_details","total_tokens"],"description":"OpenAI Responses-style usage."},"AnthropicUsage":{"type":"object","properties":{"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"cache_creation_input_tokens":{"type":"integer"},"cache_read_input_tokens":{"type":"integer"}},"required":["input_tokens","output_tokens","cache_creation_input_tokens","cache_read_input_tokens"],"description":"Anthropic-style usage."},"RoutingOptions":{"type":"object","properties":{"deadline_ms":{"type":"integer","description":"End-to-end deadline for the request. Defaults: 30 000 ms (chat-like), 60 000 ms (image/audio), 120 000 ms (video/batch).","minimum":1},"maximum_cost_usd":{"type":"number","description":"Hard cost ceiling for this request; the lower of this and the profile ceiling wins.","minimum":0},"explain":{"type":"boolean","description":"Attach a full `fabric_metadata` route explanation (unmasked node refs) to the response. Admin-oriented."},"policy":{"type":"string","description":"Accepted for forward compatibility; the resolved profile's route policy governs in this build."},"objective":{"type":"string","description":"Accepted for forward compatibility; the profile objective (`latency` | `cost` | `quality` | `balanced`) governs in this build."},"cache":{"type":"object","properties":{"mode":{"type":"string"},"scope":{"type":"string"}},"description":"Accepted for forward compatibility; the profile cache policy governs in this build."},"resilience":{"type":"object","properties":{"profile":{"type":"string"}},"description":"Accepted for forward compatibility; the profile resilience profile governs in this build."}},"description":"Enterprise routing controls (memo §4.4). Honored today: `deadline_ms`, `maximum_cost_usd`, `explain`. Remaining fields are accepted and recorded but the logical profile stays authoritative."},"ProviderPreferences":{"type":"object","properties":{"zdr":{"type":"boolean","description":"Require zero-data-retention endpoints (hard route filter)."},"only":{"type":"array","items":{"type":"string"},"description":"Restrict routing to these provider ids (hard filter)."},"order":{"type":"array","items":{"type":"string"},"description":"OpenRouter-style preference order; accepted, advisory in this build."},"allow_fallbacks":{"type":"boolean","description":"OpenRouter-compatible; accepted. The fabric's fallback graph is governed by the profile's resilience policy."},"require_parameters":{"type":"boolean","description":"OpenRouter-compatible; accepted."},"data_collection":{"type":"string","description":"OpenRouter-compatible (`allow` | `deny`); accepted."}},"description":"OpenRouter-compatible provider preference object (memo §4.4). `zdr` and `only` are enforced as hard route constraints."},"FabricMetadataGuardrail":{"type":"object","properties":{"stage":{"type":"string","enum":["PRE_ROUTE","PRE_MODEL","POST_MODEL","PRE_RETURN"]},"action":{"type":"string","enum":["allow","flag","redact","block","require_approval","restrict_route"],"description":"Most severe action taken at this stage."},"profile":{"type":"string","description":"Guardrail policy that governed the stage."},"evaluations":{"type":"integer","description":"Number of evaluator decisions at this stage."}},"required":["stage","action","profile","evaluations"]},"FabricMetadataAttempt":{"type":"object","properties":{"provider":{"type":"string"},"status":{"type":"integer","description":"200 for success, else the error-class HTTP status."},"error_type":{"$ref":"#/components/schemas/ErrorClass"}},"required":["provider","status"]},"FabricMetadata":{"type":"object","properties":{"requested":{"type":"string","description":"Model/profile string as requested."},"resolved_model":{"type":["string","null"],"description":"Canonical model that actually served the request."},"strategy":{"type":"string","description":"Routing strategy (e.g. `auto`, `pinned`)."},"policy_version":{"type":"string"},"router_version":{"type":"string"},"provider":{"type":["string","null"]},"region":{"type":["string","null"]},"account_pool":{"type":["string","null"]},"node":{"type":["object","null"],"properties":{"ref":{"type":"string","description":"Egress node ref. Masked (`node_***81`) unless the request set `routing.explain`."},"trust_tier":{"type":"string","enum":["A","B","C","D","quarantined"]}},"required":["ref","trust_tier"]},"cache":{"type":"object","properties":{"response":{"type":"string","enum":["HIT","MISS","STORED","COALESCED","BYPASS"]},"prompt_affinity":{"type":"string","enum":["HIT","MISS"]},"predicted_cached_tokens":{"type":"integer"}},"required":["response","prompt_affinity","predicted_cached_tokens"]},"guardrails":{"type":"array","items":{"$ref":"#/components/schemas/FabricMetadataGuardrail"}},"attempts":{"type":"array","items":{"$ref":"#/components/schemas/FabricMetadataAttempt"}},"routing_reason":{"type":"array","items":{"type":"string"},"description":"Human-readable routing decisions in order."}},"required":["requested","resolved_model","strategy","policy_version","router_version","provider","region","account_pool","node","cache","guardrails","attempts","routing_reason"],"description":"Opt-in route/pipeline metadata (memo §4.5, App. A.2). Attach with `routing.explain: true`, `X-Fabric-Explain: true`, or `X-OpenRouter-Metadata: enabled`. Credentials and sensitive topology are always masked for non-explain requests."},"ChatMessage":{"type":"object","properties":{"role":{"type":"string","enum":["system","developer","user","assistant","tool"]},"content":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"text":{"type":"string"}},"additionalProperties":true},"description":"Multimodal content parts (`text`, `image_url`, …)."},{"type":"null"}],"description":"Message content: plain string or content-part array."},"name":{"type":"string"},"tool_call_id":{"type":"string","description":"For `role: tool` results."},"tool_calls":{"type":"array","items":{"$ref":"#/components/schemas/ToolCall"}}},"required":["role"],"additionalProperties":true},"ToolCall":{"type":"object","properties":{"id":{"type":"string"},"type":{"const":"function","type":"string"},"function":{"type":"object","properties":{"name":{"type":"string"},"arguments":{"type":"string","description":"JSON-encoded arguments."}},"required":["name","arguments"]}},"required":["id","type","function"]},"ChatCompletionRequest":{"type":"object","properties":{"model":{"type":"string","description":"Canonical model id (`anthropic/claude-sonnet`), alias, or logical profile (`@company/general-balanced`, `fabric/auto`). Omitted → the principal's default profile."},"models":{"type":"array","items":{"type":"string"},"description":"OpenRouter fallback array. When `model` is absent the first entry becomes the primary; the fabric router owns actual fallbacks."},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"},"description":"Conversation so far. Required, non-empty."},"stream":{"type":"boolean","description":"Stream the response as OpenAI `chat.completion.chunk` SSE frames terminated by `data: [DONE]`."},"session_id":{"type":"string","description":"Sticky agent-session id: keeps model pinning and prompt-cache affinity across calls (memo §7.7)."},"max_tokens":{"type":"integer","description":"Output token cap; truncation reports `finish_reason: length`."},"max_completion_tokens":{"type":"integer","description":"Alias of `max_tokens`."},"temperature":{"type":"number"},"top_p":{"type":"number"},"tools":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"function":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"parameters":{"type":"object","properties":{},"additionalProperties":true}}}},"additionalProperties":true},"description":"OpenAI tool definitions."},"tool_choice":{"anyOf":[{"type":"string"},{"type":"object","additionalProperties":true}],"description":"`auto` | `none` | `required` | forced tool object."},"response_format":{"type":"object","properties":{"type":{"type":"string","description":"`text` | `json_object` | `json_schema`."}},"additionalProperties":true},"provider":{"$ref":"#/components/schemas/ProviderPreferences"},"routing":{"$ref":"#/components/schemas/RoutingOptions"}},"required":["messages"],"description":"OpenAI/OpenRouter-compatible chat request plus fabric extensions. Unknown fields are forwarded only when the selected endpoint declares them safe.","additionalProperties":true},"ChatCompletionChoice":{"type":"object","properties":{"index":{"type":"integer"},"message":{"type":"object","properties":{"role":{"const":"assistant","type":"string"},"content":{"type":"string"},"tool_calls":{"type":"array","items":{"$ref":"#/components/schemas/ToolCall"}}},"required":["role","content"]},"logprobs":{"type":"null"},"finish_reason":{"type":"string","description":"`stop` | `length` | `tool_calls` | `content_filter`."}},"required":["index","message","logprobs","finish_reason"]},"ChatCompletionResponse":{"type":"object","properties":{"id":{"type":"string","description":"Generation id (`gen_…`) — also the key for `GET /generations/{id}`."},"object":{"const":"chat.completion","type":"string"},"created":{"type":"integer","description":"Epoch seconds."},"model":{"type":"string","description":"Resolved canonical model id."},"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChatCompletionChoice"}},"usage":{"$ref":"#/components/schemas/Usage"},"fabric_metadata":{"$ref":"#/components/schemas/FabricMetadata"}},"required":["id","object","created","model","choices","usage"]},"ChatCompletionChunk":{"type":"object","properties":{"id":{"type":"string"},"object":{"const":"chat.completion.chunk","type":"string"},"created":{"type":"integer"},"model":{"type":"string"},"choices":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"delta":{"type":"object","properties":{"role":{"type":"string"},"content":{"type":"string"},"tool_calls":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"description":"First chunk carries `role`; content chunks carry `content`; tool chunks carry `tool_calls` with an `index` per entry."},"logprobs":{"type":"null"},"finish_reason":{"type":["string","null"]}},"required":["index","delta","logprobs","finish_reason"]}},"usage":{"$ref":"#/components/schemas/Usage"},"fabric_metadata":{"$ref":"#/components/schemas/FabricMetadata"}},"required":["id","object","created","model","choices"],"description":"SSE frame for `stream: true`. The final chunk carries `usage` (and `fabric_metadata` when requested); the stream ends with `data: [DONE]`."},"ResponsesRequest":{"type":"object","properties":{"model":{"type":"string","description":"Canonical model, alias or logical profile."},"input":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}],"description":"Prompt input (string or item array). One of `input` | `instructions` | `prompt` | `messages` is required."},"instructions":{"type":"string"},"prompt":{"type":"string"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"stream":{"type":"boolean","description":"Stream typed `response.*` SSE events (no `[DONE]` terminator)."},"session_id":{"type":"string"},"provider":{"$ref":"#/components/schemas/ProviderPreferences"},"routing":{"$ref":"#/components/schemas/RoutingOptions"}},"additionalProperties":true},"ResponseOutputMessage":{"type":"object","properties":{"id":{"type":"string","description":"`msg_…`"},"type":{"const":"message","type":"string"},"status":{"type":"string","description":"`in_progress` | `completed`."},"role":{"const":"assistant","type":"string"},"content":{"type":"array","items":{"type":"object","properties":{"type":{"const":"output_text","type":"string"},"text":{"type":"string"},"annotations":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"required":["type","text","annotations"]}}},"required":["id","type","status","role","content"]},"ResponseObject":{"type":"object","properties":{"id":{"type":"string","description":"Generation id (`gen_…`)."},"object":{"const":"response","type":"string"},"created_at":{"type":"integer","description":"Epoch seconds."},"status":{"type":"string","description":"`completed` (sync surface)."},"model":{"type":"string"},"output":{"type":"array","items":{"$ref":"#/components/schemas/ResponseOutputMessage"}},"output_text":{"type":"string","description":"Convenience concatenation of output text."},"usage":{"$ref":"#/components/schemas/ResponsesUsage"},"fabric_metadata":{"$ref":"#/components/schemas/FabricMetadata"}},"required":["id","object","created_at","status","model","output","output_text","usage"]},"AnthropicMessagesRequest":{"type":"object","properties":{"model":{"type":"string","description":"Canonical model, alias or logical profile."},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"},"description":"Anthropic-style messages (string or content-block arrays). Required, non-empty."},"system":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}]},"max_tokens":{"type":"integer"},"stream":{"type":"boolean","description":"Stream Anthropic named SSE events (`message_start` … `message_stop`, no `[DONE]`)."},"session_id":{"type":"string"},"provider":{"$ref":"#/components/schemas/ProviderPreferences"},"routing":{"$ref":"#/components/schemas/RoutingOptions"}},"required":["messages"],"additionalProperties":true},"AnthropicContentBlock":{"oneOf":[{"type":"object","properties":{"type":{"const":"text","type":"string"},"text":{"type":"string"}},"required":["type","text"]},{"type":"object","properties":{"type":{"const":"tool_use","type":"string"},"id":{"type":"string"},"name":{"type":"string"},"input":{"type":"object","properties":{},"additionalProperties":true}},"required":["type","id","name","input"]}],"description":"Anthropic content block (`text` or `tool_use`)."},"AnthropicMessageResponse":{"type":"object","properties":{"id":{"type":"string","description":"Generation id (`gen_…`)."},"type":{"const":"message","type":"string"},"role":{"const":"assistant","type":"string"},"model":{"type":"string"},"content":{"type":"array","items":{"$ref":"#/components/schemas/AnthropicContentBlock"}},"stop_reason":{"type":"string","description":"`end_turn` | `max_tokens` | `tool_use` | `refusal`."},"stop_sequence":{"type":"null"},"usage":{"$ref":"#/components/schemas/AnthropicUsage"},"fabric_metadata":{"$ref":"#/components/schemas/FabricMetadata"}},"required":["id","type","role","model","content","stop_reason","stop_sequence","usage"]},"EmbeddingsRequest":{"type":"object","properties":{"model":{"type":"string","description":"REQUIRED. Approved embedding model (`openai/text-embedding-4`), alias, or a single-model embeddings profile (`@company/embeddings`). The fabric never silently falls back across vector spaces (memo §13.4)."},"input":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Text or array of texts to embed."},"encoding_format":{"type":"string","enum":["float"],"description":"Only `float` is supported."},"routing":{"$ref":"#/components/schemas/RoutingOptions"}},"required":["model","input"],"additionalProperties":true},"EmbeddingObject":{"type":"object","properties":{"object":{"const":"embedding","type":"string"},"index":{"type":"integer"},"embedding":{"type":"array","items":{"type":"number"},"description":"Deterministic vector for the pinned model."}},"required":["object","index","embedding"]},"EmbeddingsResponse":{"type":"object","properties":{"object":{"const":"list","type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/EmbeddingObject"}},"model":{"type":"string","description":"The exact model that produced the vectors — guaranteed to match the pinned model."},"usage":{"type":"object","properties":{"prompt_tokens":{"type":"integer"},"total_tokens":{"type":"integer"}},"required":["prompt_tokens","total_tokens"]},"fabric_metadata":{"$ref":"#/components/schemas/FabricMetadata"}},"required":["object","data","model","usage"]},"RerankRequest":{"type":"object","properties":{"model":{"type":"string","description":"Optional; defaults to `@company/embeddings`."},"query":{"type":"string","description":"REQUIRED, non-empty."},"documents":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"object","properties":{"text":{"type":"string"}}}]},"description":"REQUIRED, non-empty. Strings or `{ text }` objects."},"top_n":{"type":"integer","description":"Return only the top N results."},"return_documents":{"type":"boolean","description":"Echo each result's document text."},"routing":{"$ref":"#/components/schemas/RoutingOptions"}},"required":["query","documents"],"additionalProperties":true},"RerankResult":{"type":"object","properties":{"index":{"type":"integer","description":"Index into the request `documents` array."},"relevance_score":{"type":"number","description":"0..1, higher is more relevant."},"document":{"type":"object","properties":{"text":{"type":"string"}},"description":"Present when `return_documents: true`."}},"required":["index","relevance_score"]},"RerankResponse":{"type":"object","properties":{"id":{"type":"string","description":"Generation id."},"object":{"const":"rerank","type":"string"},"model":{"type":"string"},"results":{"type":"array","items":{"$ref":"#/components/schemas/RerankResult"},"description":"Sorted by descending relevance."},"usage":{"$ref":"#/components/schemas/LedgerUsage"},"fabric_metadata":{"$ref":"#/components/schemas/FabricMetadata"}},"required":["id","object","model","results","usage"]},"SpeechRequest":{"type":"object","properties":{"model":{"type":"string","description":"Optional; defaults to `@company/voice`."},"input":{"type":"string","description":"REQUIRED, non-empty text to synthesize."},"voice":{"type":"string","description":"Voice preset; recorded on the routed request."},"response_format":{"type":"string","description":"Audio container hint (default `mp3`)."},"routing":{"$ref":"#/components/schemas/RoutingOptions"}},"required":["input"],"additionalProperties":true},"TranscriptionResponse":{"type":"object","properties":{"text":{"type":"string","description":"Transcript."},"model":{"type":"string"},"language":{"type":"string","description":"Echoed when supplied in the request."},"fabric_metadata":{"$ref":"#/components/schemas/FabricMetadata"}},"required":["text","model"]},"ImagesRequest":{"type":"object","properties":{"model":{"type":"string","description":"Optional; defaults to `@company/image`."},"prompt":{"type":"string","description":"REQUIRED, non-empty."},"n":{"type":"integer","description":"Number of images, clamped to 1..4.","minimum":1,"maximum":4,"default":1},"response_format":{"type":"string","enum":["url","b64_json"],"default":"url"},"size":{"type":"string","description":"Accepted and recorded; the simulated plane renders 1024×1024."},"routing":{"$ref":"#/components/schemas/RoutingOptions"}},"required":["prompt"],"additionalProperties":true},"ImagesResponse":{"type":"object","properties":{"created":{"type":"integer","description":"Epoch seconds."},"model":{"type":"string"},"data":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","description":"`data:image/svg+xml;…` data URL (when `response_format: url`)."},"b64_json":{"type":"string","description":"Base64 payload (when `response_format: b64_json`)."}}}},"usage":{"$ref":"#/components/schemas/LedgerUsage"},"fabric_metadata":{"$ref":"#/components/schemas/FabricMetadata"}},"required":["created","model","data","usage"]},"VideoCreateRequest":{"type":"object","properties":{"model":{"type":"string","description":"Optional; defaults to `@company/video`."},"prompt":{"type":"string","description":"REQUIRED, non-empty."},"duration_seconds":{"type":"integer","description":"Accepted and recorded on the job request."},"routing":{"$ref":"#/components/schemas/RoutingOptions"}},"required":["prompt"],"additionalProperties":true},"JobStatus":{"type":"string","enum":["queued","routing","submitted","running","succeeded","failed","cancelled"],"description":"Async job lifecycle (memo §13.3). Jobs auto-progress on every read."},"VideoJob":{"type":"object","properties":{"id":{"type":"string","description":"`job_…`"},"object":{"const":"video.generation","type":"string"},"model":{"type":"string","description":"Canonical model resolved at submit time."},"status":{"$ref":"#/components/schemas/JobStatus"},"progress":{"type":"number","description":"0..1."},"created_at":{"type":"integer","description":"Epoch seconds."},"updated_at":{"type":"integer","description":"Epoch seconds."},"polling_url":{"type":"string","description":"`/v1/videos/{id}`."},"output":{"type":"object","properties":{"artifacts":{"type":"array","items":{"$ref":"#/components/schemas/Artifact"}}},"description":"Present when `status: succeeded` — poster frame + simulated MP4 metadata."},"cost_usd":{"type":"number","description":"Settled cost, present on success."},"error":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/ErrorClass"},"message":{"type":"string"}},"description":"Present on `failed`/`cancelled`."}},"required":["id","object","model","status","progress","created_at","updated_at","polling_url"]},"BatchCreateRequest":{"type":"object","properties":{"requests":{"type":"array","items":{"type":"object","properties":{"custom_id":{"type":"string","description":"Echoed on the per-item result."},"model":{"type":"string"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}}},"description":"A chat-like request object executed through the full pipeline when the batch window is reached.","additionalProperties":true},"description":"REQUIRED, 1..20 items."},"routing":{"$ref":"#/components/schemas/RoutingOptions"}},"required":["requests"],"additionalProperties":true},"BatchItemResult":{"type":"object","properties":{"index":{"type":"integer"},"custom_id":{"type":["string","null"]},"status":{"type":"string","enum":["succeeded","failed"]},"status_code":{"type":"integer"},"response":{"type":"object","properties":{},"description":"Chat-completion-shaped body on success.","additionalProperties":true},"error":{"type":"object","properties":{},"description":"OpenAI wire error body on failure.","additionalProperties":true}},"required":["index","custom_id","status","status_code"]},"BatchJob":{"type":"object","properties":{"id":{"type":"string","description":"`job_…`"},"object":{"const":"batch","type":"string"},"status":{"$ref":"#/components/schemas/JobStatus"},"progress":{"type":"number","description":"0..1."},"profile":{"type":"string","description":"Logical profile the items execute under."},"model":{"type":"string"},"request_counts":{"type":"object","properties":{"total":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"}},"required":["total","completed","failed"]},"created_at":{"type":"integer"},"updated_at":{"type":"integer"},"polling_url":{"type":"string","description":"`/v1/batches/{id}`."},"results":{"type":"array","items":{"$ref":"#/components/schemas/BatchItemResult"},"description":"Per-item results once the batch has executed."},"error":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/ErrorClass"},"message":{"type":"string"}}}},"required":["id","object","status","progress","profile","model","request_counts","created_at","updated_at","polling_url"]},"FileRegisterRequest":{"type":"object","properties":{"filename":{"type":"string","description":"REQUIRED (alias: `name`)."},"mime_type":{"type":"string","description":"Default `application/octet-stream` (alias: `content_type`)."},"size_bytes":{"type":"integer","description":"Default 0 (alias: `bytes`)."},"sha256":{"type":"string","description":"Content hash (alias: `hash`)."},"classification":{"type":"string","enum":["public","internal","confidential","restricted"],"default":"internal"},"retention_days":{"type":"integer","description":"Default 30."},"purpose":{"type":"string","description":"OpenAI-style purpose, default `assistants`."}},"required":["filename"],"description":"Metadata-only registration: no bytes transit the gateway (memo §13.2 — production clients upload directly to R2 via presigned URL)."},"FileObject":{"type":"object","properties":{"id":{"type":"string","description":"`file_…`"},"object":{"const":"file","type":"string"},"filename":{"type":"string"},"bytes":{"type":"integer"},"purpose":{"type":"string"},"status":{"const":"processed","type":"string"},"mime_type":{"type":"string"},"sha256":{"type":["string","null"]},"classification":{"type":"string"},"retention_days":{"type":"integer"},"created_at":{"type":"integer","description":"Epoch seconds."}},"required":["id","object","filename","bytes","purpose","status","mime_type","sha256","classification","retention_days","created_at"]},"ArtifactRegisterRequest":{"type":"object","properties":{"name":{"type":"string","description":"REQUIRED (alias: `filename`)."},"mime_type":{"type":"string","description":"REQUIRED (alias: `content_type`)."},"size_bytes":{"type":"integer","description":"Default 0."},"sha256":{"type":"string"},"classification":{"type":"string","enum":["public","internal","confidential","restricted"],"default":"internal"},"retention_days":{"type":"integer","description":"Default 30."},"job_id":{"type":"string","description":"Link to the producing job."},"generation_id":{"type":"string","description":"Link to the producing generation."}},"required":["name","mime_type"],"description":"Metadata-only artifact registration (memo §13.2)."},"Artifact":{"type":"object","properties":{"id":{"type":"string","description":"`art_…` (or `file_…` for the files surface)."},"object":{"const":"artifact","type":"string"},"kind":{"type":"string","enum":["image","video","audio","file"]},"name":{"type":["string","null"]},"mime_type":{"type":"string"},"size_bytes":{"type":"integer"},"sha256":{"type":["string","null"]},"classification":{"type":"string"},"retention_days":{"type":"integer"},"scan_result":{"type":"string","enum":["clean","pending","flagged"]},"job_id":{"type":["string","null"]},"generation_id":{"type":["string","null"]},"data_url":{"type":["string","null"],"description":"Inline data URL for small simulated artifacts (e.g. video poster frames)."},"metadata":{"type":["object","null"],"properties":{},"additionalProperties":true},"created_at":{"type":"integer","description":"Epoch seconds."}},"required":["id","object","kind","name","mime_type","size_bytes","sha256","classification","retention_days","scan_result","job_id","generation_id","data_url","metadata","created_at"]},"ModerationCategory":{"type":"string","description":"Moderation category key. The standard OpenAI omni set plus fabric DLP-oriented extension categories.","enum":["harassment","harassment/threatening","hate","hate/threatening","illicit","illicit/violent","self-harm","self-harm/intent","self-harm/instructions","sexual","sexual/minors","violence","violence/graphic","fabric/secrets","fabric/pii","fabric/dlp","fabric/prompt-injection"]},"ModerationsRequest":{"type":"object","properties":{"input":{"anyOf":[{"type":"string"},{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"object","properties":{"type":{"type":"string"},"text":{"type":"string"}},"additionalProperties":true}]}}],"description":"REQUIRED. Text, or an array of texts / content parts. Non-text parts (e.g. `image_url`) score 0 in this core."},"model":{"type":"string","description":"Echoed back; defaults to `fabric-moderation-v1`. Moderation is served by the fabric's own evaluators, not a provider call."}},"required":["input"],"additionalProperties":true},"ModerationResult":{"type":"object","properties":{"flagged":{"type":"boolean","description":"True when any category fired."},"categories":{"type":"object","additionalProperties":{"type":"boolean"},"propertyNames":{"$ref":"#/components/schemas/ModerationCategory"},"description":"Every category key → fired boolean. **All keys are always present** (unfired categories are `false`). Keys: the OpenAI omni set (`harassment`, `harassment/threatening`, `hate`, `hate/threatening`, `illicit`, `illicit/violent`, `self-harm`, `self-harm/intent`, `self-harm/instructions`, `sexual`, `sexual/minors`, `violence`, `violence/graphic`) plus the fabric extensions (`fabric/secrets`, `fabric/pii`, `fabric/dlp`, `fabric/prompt-injection`)."},"category_scores":{"type":"object","additionalProperties":{"type":"number"},"propertyNames":{"$ref":"#/components/schemas/ModerationCategory"},"description":"Same keys as `categories`, each mapped to a deterministic 0..1 severity score derived from the guardrail action (`block` 0.9 / `redact` 0.7 / else 0.4) plus 0.02 per match, capped at 0.99."}},"required":["flagged","categories","category_scores"]},"ModerationsResponse":{"type":"object","properties":{"id":{"type":"string","description":"`modr_…` (derived from the ledgered generation id)."},"model":{"type":"string"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ModerationResult"},"description":"One result per input item, in request order."}},"required":["id","model","results"]},"RealtimeSessionRequest":{"type":"object","properties":{"model":{"type":"string","description":"Canonical model or logical profile; defaults to `@company/voice`."},"voice":{"type":"string","description":"Voice preset; defaults to `alloy`."},"modalities":{"type":"array","items":{"type":"string"},"description":"Defaults to `[\"audio\", \"text\"]`."}},"additionalProperties":true},"RealtimeSession":{"type":"object","properties":{"id":{"type":"string","description":"`rtsess_…`"},"object":{"const":"realtime.session","type":"string"},"model":{"type":"string","description":"Model the session is pinned to."},"voice":{"type":"string"},"modalities":{"type":"array","items":{"type":"string"}},"created_at":{"type":"integer","description":"Epoch seconds."},"expires_at":{"type":"integer","description":"Epoch seconds — session descriptors are short-lived."},"client_secret":{"type":"object","properties":{"value":{"type":"string","description":"Ephemeral `fab_rt_…` secret for the client transport."},"expires_at":{"type":"integer"}},"required":["value","expires_at"]},"fabric_metadata":{"type":"object","properties":{"requested":{"type":"string"},"resolved_model":{"type":"string"},"placement":{"type":["object","null"],"properties":{"provider":{"type":"string"},"region":{"type":"string"},"account_pool":{"type":"string"},"node":{"type":"object","properties":{"ref":{"type":"string","description":"Masked unless `routing.explain`."},"trust_tier":{"type":"string"}},"required":["ref","trust_tier"]},"zdr":{"type":"boolean"}},"required":["provider","region","account_pool","node","zdr"]},"note":{"type":"string","description":"Explains the route-at-session-creation semantics and, in this core, that no socket is opened."}},"required":["requested","resolved_model","placement","note"]}},"required":["id","object","model","voice","modalities","created_at","expires_at","client_secret","fabric_metadata"]},"FeedbackRequest":{"type":"object","properties":{"generation_id":{"type":"string","description":"REQUIRED. Id of a ledgered generation (`gen_…`) — take one from `GET /generations` or the `id` of any completion response."},"rating":{"type":"integer","enum":[-1,1],"description":"REQUIRED. `1` positive, `-1` negative."},"comment":{"type":"string","description":"Optional free text, at most 2000 characters."}},"required":["generation_id","rating"]},"Feedback":{"type":"object","properties":{"id":{"type":"string","description":"`fb_…`"},"object":{"const":"feedback","type":"string"},"generation_id":{"type":"string"},"principal_id":{"type":"string","description":"Principal that submitted the rating."},"rating":{"type":"integer","enum":[-1,1]},"comment":{"type":["string","null"]},"created_at":{"type":"integer","description":"Epoch seconds."}},"required":["id","object","generation_id","principal_id","rating","comment","created_at"]},"ModelPricing":{"type":"object","properties":{"provider":{"type":"string"},"input_per_mtok":{"type":"number","description":"USD per million input tokens."},"output_per_mtok":{"type":"number"},"cached_input_per_mtok":{"type":"number"}},"required":["provider","input_per_mtok","output_per_mtok","cached_input_per_mtok"]},"Model":{"type":"object","properties":{"id":{"type":"string","description":"Canonical model id (`anthropic/claude-sonnet`) or logical profile id (`@company/general-fast`)."},"object":{"const":"model","type":"string"},"created":{"type":"integer"},"owned_by":{"type":"string"},"type":{"type":"string","enum":["model","profile"]},"display_name":{"type":"string"},"lifecycle":{"type":"string","description":"`approved` | `preview` | `deprecated` | `retired` (profiles always `approved`)."},"capabilities":{"type":["object","null"],"properties":{"modalities_in":{"type":"array","items":{"type":"string"}},"modalities_out":{"type":"array","items":{"type":"string"}},"tools":{"type":"boolean"},"structured_output":{"type":"boolean"},"streaming":{"type":"boolean"}},"required":["modalities_in","modalities_out","tools","structured_output","streaming"]},"context_tokens":{"type":["integer","null"]},"max_output_tokens":{"type":["integer","null"]},"aliases":{"type":"array","items":{"type":"string"}},"pricing":{"type":"array","items":{"$ref":"#/components/schemas/ModelPricing"},"description":"Per-provider price cards, cheapest input price first."},"fabric_profile":{"type":"object","properties":{"version":{"type":"integer"},"description":{"type":"string"},"objective":{"type":"string"},"allowed_models":{"type":"array","items":{"type":"string"}},"guardrail_policy":{"type":"string"},"route_policy":{"type":"string"},"cache_mode":{"type":"string"},"resilience_profile":{"type":"string"},"max_cost_usd":{"type":"number"},"audit_mode":{"type":"string"}},"description":"Present on `type: profile` entries only."}},"required":["id","object","created","owned_by","type","display_name","lifecycle","capabilities","context_tokens","max_output_tokens","aliases","pricing"]},"Generation":{"type":"object","properties":{"id":{"type":"string","description":"`gen_…`"},"object":{"const":"generation","type":"string"},"created":{"type":"integer","description":"Epoch seconds."},"created_at":{"type":"integer","description":"Epoch milliseconds."},"status":{"type":"string","enum":["pending","running","succeeded","failed","blocked","cancelled"]},"operation":{"type":"string","description":"`chat` | `messages` | `responses` | `embeddings` | `rerank` | `speech` | `transcription` | `image` | `video` | `batch`."},"principal_id":{"type":"string"},"project_id":{"type":"string"},"profile_id":{"type":"string"},"requested_model":{"type":"string"},"model":{"type":["string","null"],"description":"Resolved canonical model."},"cache_state":{"type":"string","description":"`HIT` | `MISS` | `STORED` | `COALESCED` | `BYPASS`."},"latency_ms":{"type":"integer"},"cost_usd":{"type":"number"},"usage":{"$ref":"#/components/schemas/LedgerUsage"},"attempt_count":{"type":"integer"},"guardrail_decision_count":{"type":"integer"},"session_id":{"type":"string"},"error":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/ErrorClass"},"message":{"type":"string"}}}},"required":["id","object","created","created_at","status","operation","principal_id","project_id","profile_id","requested_model","model","cache_state","latency_ms","cost_usd","usage","attempt_count","guardrail_decision_count"]},"Attempt":{"type":"object","properties":{"id":{"type":"string"},"no":{"type":"integer","description":"Attempt ordinal within the fallback tree."},"provider":{"type":"string"},"account_id":{"type":"string"},"node_id":{"type":"string"},"endpoint_id":{"type":"string"},"status":{"type":"string"},"latency_ms":{"type":"integer"},"started_at":{"type":"integer"},"error_class":{"$ref":"#/components/schemas/ErrorClass"},"error_message":{"type":"string"},"usage":{"$ref":"#/components/schemas/LedgerUsage"}},"required":["id","no","provider","account_id","node_id","endpoint_id","status","latency_ms","started_at"]},"GuardrailDecision":{"type":"object","properties":{"id":{"type":"string"},"stage":{"type":"string","enum":["PRE_ROUTE","PRE_MODEL","POST_MODEL","PRE_RETURN"]},"evaluator":{"type":"string","description":"e.g. `secrets-scanner`, `pii-redactor`, `content-policy`."},"action":{"type":"string","enum":["allow","flag","redact","block","require_approval","restrict_route"]},"detail":{"type":"string"},"created_at":{"type":"integer"}},"required":["id","stage","evaluator","action","detail","created_at"]},"RouteCandidate":{"type":"object","properties":{"ref":{"type":"string"},"model":{"type":"string"},"provider":{"type":"string"},"region":{"type":"string"},"account_pool":{"type":"string"},"contract":{"type":"string","description":"Supply contract kind."},"zdr":{"type":"boolean"},"node":{"type":"object","properties":{"id":{"type":"string"},"trust_tier":{"type":"string"},"region":{"type":"string"}},"required":["id","trust_tier","region"]}},"required":["ref","model","provider","region","account_pool","contract","zdr","node"]},"RouteExplanation":{"type":"object","properties":{"objective":{"type":"string"},"router_version":{"type":"string"},"policy_version":{"type":"string"},"selected":{"$ref":"#/components/schemas/RouteCandidate"},"scores":{"type":"array","items":{"type":"object","properties":{"candidate":{"type":"string"},"total":{"type":"number"},"components":{"type":"object","properties":{},"additionalProperties":true}},"required":["candidate","total","components"]}},"hard_filter_rejections":{"type":"array","items":{"type":"object","properties":{"candidate":{"type":"string"},"reason":{"type":"string"}},"required":["candidate","reason"]}},"fallback_chain":{"type":"array","items":{"$ref":"#/components/schemas/RouteCandidate"}}},"required":["objective","router_version","policy_version","selected","scores","hard_filter_rejections","fallback_chain"],"description":"Route plan scores, hard-filter rejections and the fallback chain (memo §7.6). Null when the request never reached routing (e.g. PRE_ROUTE block)."},"GenerationDetail":{"allOf":[{"$ref":"#/components/schemas/Generation"},{"type":"object","properties":{"attempts":{"type":"array","items":{"$ref":"#/components/schemas/Attempt"}},"guardrail_decisions":{"type":"array","items":{"$ref":"#/components/schemas/GuardrailDecision"}},"timeline":{"type":"array","items":{"type":"object","properties":{"at":{"type":"integer"},"stage":{"type":"string"},"detail":{"type":"string"}},"required":["at","stage","detail"]},"description":"Full audit-ledger timeline."},"route_explanation":{"anyOf":[{"$ref":"#/components/schemas/RouteExplanation"},{"type":"null"}]}},"required":["attempts","guardrail_decisions","timeline","route_explanation"]}],"description":"The full audit record for one generation (memo §14.4)."}}},"x-fabric-error-classes":[{"class":"authentication_failed","http_status":401,"retryable":true,"openai_type":"authentication_error","description":"API key or provider credential rejected. Internally the fabric quarantines the credential and retries an alternate; at the edge it is a 401."},{"class":"credential_expired","http_status":401,"retryable":true,"openai_type":"authentication_error","description":"Provider credential expired; refreshed or replaced where authorized."},{"class":"rate_limited","http_status":429,"retryable":true,"openai_type":"rate_limit_error","description":"Provider or gateway rate limit. Fallback tries alternate account/deployment/contract, same model first."},{"class":"quota_exhausted","http_status":429,"retryable":true,"openai_type":"insufficient_quota","description":"A quota pool is exhausted; alternate account or contract may be tried."},{"class":"egress_unavailable","http_status":502,"retryable":true,"openai_type":"api_error","description":"No healthy egress node for the required trust tier/region."},{"class":"provider_overloaded","http_status":503,"retryable":true,"openai_type":"overloaded_error","description":"Provider returned an overload signal; alternate endpoint/provider for the same canonical model."},{"class":"provider_unavailable","http_status":503,"retryable":true,"openai_type":"api_error","description":"Provider endpoint down or unreachable."},{"class":"network_timeout","http_status":504,"retryable":true,"openai_type":"timeout_error","description":"Attempt exceeded its deadline; one bounded retry if the request deadline permits."},{"class":"unsupported_parameter","http_status":400,"retryable":false,"openai_type":"invalid_request_error","description":"A parameter the selected endpoint cannot honor exactly."},{"class":"unsupported_modality","http_status":400,"retryable":false,"openai_type":"invalid_request_error","description":"The operation/modality is not supported by any allowed endpoint."},{"class":"context_too_long","http_status":400,"retryable":false,"openai_type":"invalid_request_error","description":"Input exceeds the model context window. Moving to a larger-context model is a routing decision, never a silent retry."},{"class":"invalid_structured_output","http_status":502,"retryable":true,"openai_type":"api_error","description":"Model output failed schema validation; repair retry, then a schema-compatible model."},{"class":"content_policy_rejection","http_status":403,"retryable":false,"openai_type":"content_policy_violation","description":"Guardrail content block. NEVER retried on a more permissive model."},{"class":"dlp_block","http_status":403,"retryable":false,"openai_type":"content_policy_violation","description":"Data-loss-prevention block (secrets/PII egress). Never retryable."},{"class":"tool_execution_failed","http_status":502,"retryable":false,"openai_type":"api_error","description":"A tool call failed; retry policy respects tool idempotency declarations."},{"class":"invalid_request","http_status":400,"retryable":false,"openai_type":"invalid_request_error","description":"Malformed request (bad JSON, missing fields, unknown enum values). Also used with status 404 for unknown resource ids."},{"class":"budget_exceeded","http_status":402,"retryable":false,"openai_type":"insufficient_quota","description":"The request would exceed a hard budget ceiling."},{"class":"internal","http_status":500,"retryable":false,"openai_type":"api_error","description":"Unexpected fabric-internal failure."}],"x-fabric-profiles":[{"id":"@company/general-fast","description":"Low-latency default for interactive product surfaces."},{"id":"@company/general-balanced","description":"Balanced quality/cost for most internal workloads."},{"id":"@company/general-best","description":"Maximum quality for hard reasoning and drafting."},{"id":"@company/code-production","description":"Production code generation and review; ZDR enforced."},{"id":"@company/confidential","description":"Restricted data: SG region, Tier A/B egress, ZDR, strict DLP."},{"id":"@company/vision","description":"Image understanding and document vision."},{"id":"@company/embeddings","description":"Deterministic embeddings; never silently changes model or dimensions."},{"id":"@company/voice","description":"Speech synthesis and transcription."},{"id":"@company/image","description":"Marketing and product image generation."},{"id":"@company/video","description":"Async video generation jobs."},{"id":"@company/auto","description":"Fabric auto-routing across the full approved set."},{"id":"fabric/auto","description":"Alias of @company/auto for OpenRouter-style clients."}],"x-fabric-headers":{"request":[{"name":"X-Fabric-Explain","description":"`true` → attach full `fabric_metadata` with unmasked node refs (admin-oriented). Equivalent to `routing.explain: true`."},{"name":"X-OpenRouter-Metadata","description":"`enabled` → attach `fabric_metadata` (node refs stay masked)."},{"name":"X-AI-Data-Classification","description":"Explicit data classification for routing/guardrails: `public` | `internal` | `confidential` | `restricted`. Otherwise sniffed, and the egress classifier can only tighten it."}],"response":[{"name":"x-fabric-generation-id","description":"Ledger id of the generation behind this response (data-plane endpoints)."},{"name":"x-fabric-model","description":"Resolved canonical model (binary responses such as /audio/speech)."},{"name":"x-fabric-metadata","description":"JSON-encoded FabricMetadata on binary responses when metadata was requested."}]}}