{"openapi":"3.1.0","info":{"title":"Conduit Router","version":"0.7.0","description":"Policy-first BYOK model router. OpenAI-compatible surface plus a native signed-config API, an MCP server, receipts you can verify, and standing per-key policy (mandates). Provider keys are the caller's own, envelope-encrypted at rest, never logged.","contact":{"name":"Pipavia","email":"info@pipavia.com","url":"https://pipavia.com"},"license":{"name":"Proprietary (API terms at /llms.txt)","url":"https://router.pipavia.com/llms.txt"}},"servers":[{"url":"https://router.pipavia.com"}],"paths":{"/health":{"get":{"summary":"Service probe (version, state backend)","tags":["meta"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/":{"get":{"summary":"Dashboard (web app)","tags":["human"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/dashboard":{"get":{"summary":"Dashboard (web app)","tags":["human"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/verify":{"get":{"summary":"Public receipt-verification page (checks run in your browser)","tags":["human"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/openapi.json":{"get":{"summary":"This OpenAPI document","tags":["meta"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/llms.txt":{"get":{"summary":"The router surface in one file, for agents","tags":["meta"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/.well-known/oauth-protected-resource":{"get":{"summary":"RFC 9728 protected-resource metadata for the MCP surface","tags":["discovery"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/.well-known/oauth-protected-resource/mcp":{"get":{"summary":"RFC 9728 protected-resource metadata (MCP path variant)","tags":["discovery"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/.well-known/mcp/server-card.json":{"get":{"summary":"MCP server card for registries and scanners","tags":["discovery"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/.well-known/agent-card.json":{"get":{"summary":"A2A agent card","tags":["discovery"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/.well-known/conduit/status.json":{"get":{"summary":"Machine-readable service status","tags":["discovery"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/.well-known/conduit/anchor-key.json":{"get":{"summary":"Published anchor public key for independent receipt verification (404 when anchors are HMAC-only)","tags":["discovery"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/mcp":{"post":{"summary":"MCP server (stateless JSON-RPC: initialize, tools/list, tools/call)","tags":["mcp"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/trial":{"post":{"summary":"Mint a self-serve trial key (IP rate-limited)","tags":["keys"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/trial/config":{"post":{"summary":"Mint a signed trial config","tags":["keys"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/models":{"get":{"summary":"Model catalog — OpenAI shape by default, native with ?format=conduit","tags":["catalog"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/chat/completions":{"post":{"summary":"OpenAI-compatible chat completions (streaming via stream:true)","tags":["routing"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/route":{"post":{"summary":"Native gateway call (signed-config handshake; stream:true streams)","tags":["routing"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/config":{"post":{"summary":"Set the key's standing terms (mandate)","tags":["account"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/policy":{"get":{"summary":"Read the key's standing terms + kill state","tags":["account"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/usage":{"get":{"summary":"Cumulative meter + today's spend + stored providers","tags":["account"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/billing/webhook":{"post":{"summary":"Paddle webhook receiver (signature-authenticated; test mode in this release)","tags":["billing"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/billing/claim":{"post":{"summary":"Bind a paid Paddle subscription to your key (subscription id proof; trial keys refused)","tags":["billing"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/billing/status":{"get":{"summary":"Your tier, subscription binding, and the billing mode","tags":["billing"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/receipts/{id}":{"get":{"summary":"One call's audit receipt + chain proof (owner-scoped)","tags":["audit"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/audit/anchor":{"get":{"summary":"Latest persisted signed chain-head checkpoint (anchor)","tags":["audit"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/audit/anchors":{"get":{"summary":"Published anchor history for independent verification","tags":["audit"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/audit/verify":{"post":{"summary":"Verify a receipt record against the chain (public, rate-limited)","tags":["audit"],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/byok":{"get":{"summary":"List stored provider ids (never key material)","tags":["byok"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}},"post":{"summary":"Store a provider key (envelope-encrypted)","tags":["byok"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/byok/{provider}":{"delete":{"summary":"Remove a stored provider key","tags":["byok"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/endpoints":{"post":{"summary":"Register a custom OpenAI-compatible endpoint","tags":["endpoints"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}},"get":{"summary":"List your custom endpoints","tags":["endpoints"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/v1/endpoints/{id}":{"delete":{"summary":"Remove a custom endpoint","tags":["endpoints"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/admin/keys":{"post":{"summary":"Register a Conduit key (admin)","tags":["admin"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/admin/byok":{"post":{"summary":"Register a BYOK provider key (admin)","tags":["admin"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/admin/audit/verify":{"get":{"summary":"Verify the whole audit chain (admin)","tags":["admin"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}},"/admin/audit/anchor":{"post":{"summary":"Persist a signed anchor of the current chain head (admin; idempotent)","tags":["admin"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK (SSE streams answer text/event-stream where noted)"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayError"}}}},"401":{"description":"Missing or unknown Conduit key"},"402":{"description":"Budget or quota block (fail-closed, before any provider call)"},"429":{"description":"Rate limited by the provider or the gateway"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A Conduit key (trial_… self-serve, or a registered key). Admin routes take the admin secret instead."}},"schemas":{"GatewayError":{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"object","properties":{"status":{"type":"integer"},"code":{"type":"string"},"detail":{"type":"string"}},"required":["status","code","detail"]},"_meta":{"$ref":"#/components/schemas/Meta"}}},"Meta":{"type":"object","description":"Gateway provenance carried on every routed response.","properties":{"request_id":{"type":"string"},"key_id":{"type":["string","null"]},"provider":{"type":["string","null"]},"model_requested":{"type":["string","null"]},"model_served":{"type":["string","null"]},"fallback_taken":{"type":"boolean"},"fallback_declared":{"type":"boolean"},"usage":{"type":"object","properties":{"prompt_tokens":{"type":"integer"},"completion_tokens":{"type":"integer"}}},"latency_ms":{"type":"number"},"receipt_id":{"type":["string","null"],"description":"rcpt_<seq> — fetch it at GET /v1/receipts/{id}"},"outcome":{"type":["string","null"]}}},"ChatCompletionRequest":{"type":"object","required":["messages"],"properties":{"model":{"type":"string","description":"\"provider:model\", \"custom:<endpoint_id>:<model>\", or a bare catalog model id. Omit to use your standing terms."},"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["system","user","assistant","tool"]},"content":{"type":["string","null"]},"tool_calls":{"type":"array","items":{"type":"object"}},"tool_call_id":{"type":"string"}},"required":["role"]}},"tools":{"type":"array","items":{"type":"object"}},"stream":{"type":"boolean","default":false},"max_tokens":{"type":"integer"},"temperature":{"type":"number"},"conduit":{"type":"object","description":"Conduit extensions: per-call overrides of your standing terms.","properties":{"task_profile":{"type":"string","enum":["reasoning","tool-use","bulk"]},"fallback_chain":{"type":"array","items":{"type":"string"}},"region":{"type":"string"},"budget":{"type":"object","properties":{"max_cost_per_request_usd":{"type":"number"},"max_cost_per_day_usd":{"type":"number"}}}}}}},"MandateTerms":{"type":"object","properties":{"task_profile":{"type":"string","enum":["reasoning","tool-use","bulk"]},"budget":{"type":"object","properties":{"max_cost_per_request_usd":{"type":"number"},"max_cost_per_day_usd":{"type":"number"}}},"model_allowlist":{"type":"array","items":{"type":"string"}},"fallback_chain":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string"},"model":{"type":"string"}},"required":["provider","model"]}},"region":{"type":"string"},"dev":{"type":"boolean"}}}}}}