{"openapi":"3.1.0","info":{"title":"plaingateway API","version":"1.0.0","description":"OpenRouter-compatible LLM gateway. Every path below is also served under /v1 on the same host. A key (sk-pg-v1-...) comes from the dashboard; no API creates keys."},"servers":[{"url":"https://api.plaingateway.com/api/v1"}],"security":[{"bearer":[]},{"apiKey":[]}],"paths":{"/chat/completions":{"post":{"operationId":"chat_completions","summary":"Create a chat completion","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRequest"}}}},"responses":{"200":{"description":"The completion, or a stream when stream is true.","headers":{"X-PG-Host":{"description":"The serving host, or none.","schema":{"type":"string"}},"X-PG-Cost-USD":{"description":"The charge in USD. On a stream it is an HTTP trailer.","schema":{"type":"string"}},"X-Generation-Id":{"description":"The generation id for GET /generation.","schema":{"type":"string"}},"X-PG-Request-Id":{"description":"Same value as X-Generation-Id.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletion"}},"text/event-stream":{"schema":{"type":"string","description":"Server-sent events. `: PLAINGATEWAY PROCESSING` comment lines keep the connection open while the host has not answered."}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"404":{"$ref":"#/components/responses/E404"},"408":{"$ref":"#/components/responses/E408"},"413":{"$ref":"#/components/responses/E413"},"429":{"$ref":"#/components/responses/E429"},"502":{"$ref":"#/components/responses/E502"},"503":{"$ref":"#/components/responses/E503"}}}},"/completions":{"post":{"operationId":"completions","summary":"Create a legacy text completion","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletionRequest"}}}},"responses":{"200":{"description":"The completion, or a stream when stream is true.","headers":{"X-PG-Host":{"description":"The serving host, or none.","schema":{"type":"string"}},"X-PG-Cost-USD":{"description":"The charge in USD. On a stream it is an HTTP trailer.","schema":{"type":"string"}},"X-Generation-Id":{"description":"The generation id for GET /generation.","schema":{"type":"string"}},"X-PG-Request-Id":{"description":"Same value as X-Generation-Id.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TextCompletion"}},"text/event-stream":{"schema":{"type":"string","description":"Server-sent events. `: PLAINGATEWAY PROCESSING` comment lines keep the connection open while the host has not answered."}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"404":{"$ref":"#/components/responses/E404"},"408":{"$ref":"#/components/responses/E408"},"413":{"$ref":"#/components/responses/E413"},"429":{"$ref":"#/components/responses/E429"},"502":{"$ref":"#/components/responses/E502"},"503":{"$ref":"#/components/responses/E503"}}}},"/messages":{"post":{"operationId":"messages","summary":"Create an Anthropic-shaped message","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagesRequest"}}}},"responses":{"200":{"description":"The message, or a stream when stream is true.","headers":{"X-PG-Host":{"description":"The serving host, or none.","schema":{"type":"string"}},"X-PG-Cost-USD":{"description":"The charge in USD. On a stream it is an HTTP trailer.","schema":{"type":"string"}},"X-Generation-Id":{"description":"The generation id for GET /generation.","schema":{"type":"string"}},"X-PG-Request-Id":{"description":"Same value as X-Generation-Id.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}},"text/event-stream":{"schema":{"type":"string","description":"Server-sent events. `: PLAINGATEWAY PROCESSING` comment lines keep the connection open while the host has not answered."}}}},"default":{"description":"Error in Anthropic's shape.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnthropicError"}}}}},"description":"Anthropic Messages shape. Errors on this path use the Anthropic error shape. Anthropic-Version and Anthropic-Beta headers are passed to Anthropic hosts."}},"/responses":{"post":{"operationId":"responses","summary":"Create an OpenAI Responses-shaped result","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponsesRequest"}}}},"responses":{"200":{"description":"The completion, or a stream when stream is true.","headers":{"X-PG-Host":{"description":"The serving host, or none.","schema":{"type":"string"}},"X-PG-Cost-USD":{"description":"The charge in USD. On a stream it is an HTTP trailer.","schema":{"type":"string"}},"X-Generation-Id":{"description":"The generation id for GET /generation.","schema":{"type":"string"}},"X-PG-Request-Id":{"description":"Same value as X-Generation-Id.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Response"}},"text/event-stream":{"schema":{"type":"string","description":"Server-sent events. `: PLAINGATEWAY PROCESSING` comment lines keep the connection open while the host has not answered."}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"402":{"$ref":"#/components/responses/E402"},"404":{"$ref":"#/components/responses/E404"},"408":{"$ref":"#/components/responses/E408"},"413":{"$ref":"#/components/responses/E413"},"429":{"$ref":"#/components/responses/E429"},"502":{"$ref":"#/components/responses/E502"},"503":{"$ref":"#/components/responses/E503"}}}},"/models":{"get":{"operationId":"models","summary":"List routed models with prices","security":[],"responses":{"200":{"description":"The catalog.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelList"}}}}}}},"/models/{author}/{slug}/endpoints":{"get":{"operationId":"model_endpoints","summary":"List the hosts that serve one model","security":[],"parameters":[{"name":"author","in":"path","required":true,"schema":{"type":"string"},"example":"openai"},{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"example":"gpt-5.6-luna"}],"responses":{"200":{"description":"The model's hosts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelEndpoints"}}}},"404":{"$ref":"#/components/responses/E404"},"500":{"$ref":"#/components/responses/E500"}}}},"/generation":{"get":{"operationId":"generation","summary":"Cost and usage of one request","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string","pattern":"^gen-"},"description":"The X-Generation-Id of a request made by this account."}],"responses":{"200":{"description":"The generation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Generation"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"503":{"$ref":"#/components/responses/E503"}}}},"/credits":{"get":{"operationId":"credits","summary":"Total credits and usage of the account","responses":{"200":{"description":"Totals in USD. Spendable balance is total_credits minus total_usage.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Credits"}}}},"401":{"$ref":"#/components/responses/E401"},"503":{"$ref":"#/components/responses/E503"}}}},"/auth/key":{"get":{"operationId":"auth_key","summary":"The calling key's limit and usage","responses":{"200":{"description":"The calling key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyInfo"}}}},"401":{"$ref":"#/components/responses/E401"},"503":{"$ref":"#/components/responses/E503"}}}},"/healthz":{"get":{"operationId":"healthz","summary":"Gateway health","servers":[{"url":"https://api.plaingateway.com"}],"security":[],"responses":{"200":{"description":"Always 200. degraded means an upstream host is down or not checked yet.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded"]}},"required":["status"]}}}}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Authorization: Bearer sk-pg-v1-..."},"apiKey":{"type":"apiKey","in":"header","name":"X-Api-Key","description":"Anthropic SDKs and Claude Code send the key here."}},"responses":{"E400":{"description":"Invalid JSON, a missing or unknown model id, an unsupported variant, a bad provider object, or plugins or transforms set.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E401":{"description":"No key, or the key is unknown, disabled or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E402":{"description":"The account balance is too low for this request, or the key reached its spend limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404":{"description":"Not found. On a completion: no host is left after the provider filters; metadata has routing_funnel and failed_routing_step.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E408":{"description":"The host timed out.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E413":{"description":"The request body is over 32 MiB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E429":{"description":"The last host rate limited the request. Retry-After is passed through when the host sends it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E500":{"description":"The catalog entry could not be read.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E502":{"description":"The host returned an error or an unreadable response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E503":{"description":"A gateway store (keys, billing or usage) is unavailable; retry shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"message":{"type":"string"},"code":{"type":"integer","description":"The HTTP status."},"metadata":{"type":"object","additionalProperties":true}},"required":["message","code"]},"user_id":{"type":"string","description":"Sent on 400 once the key is known."}},"required":["error"]},"AnthropicError":{"type":"object","properties":{"type":{"const":"error"},"error":{"type":"object","properties":{"type":{"type":"string","example":"authentication_error"},"message":{"type":"string"},"error_type":{"type":"string","example":"authentication"}}},"request_id":{"type":["string","null"]}}},"ProviderPreferences":{"type":"object","additionalProperties":false,"properties":{"order":{"type":"array","items":{"type":"string"}},"only":{"type":"array","items":{"type":"string"}},"ignore":{"type":"array","items":{"type":"string"}},"sort":{"oneOf":[{"type":"string","enum":["price","throughput","latency"]},{"type":"object","properties":{"by":{"type":"string","enum":["price","throughput","latency"]}}}]},"allow_fallbacks":{"type":"boolean"},"data_collection":{"type":"string","enum":["allow","deny"]},"zdr":{"type":"boolean"},"quantizations":{"type":"array","items":{"type":"string"}},"max_price":{"type":"object","additionalProperties":false,"properties":{"prompt":{"type":"number"},"completion":{"type":"number"}},"description":"USD per 1M tokens."}}},"Usage":{"type":"object","properties":{"prompt_tokens":{"type":"integer"},"completion_tokens":{"type":"integer"},"total_tokens":{"type":"integer"},"cost":{"type":"number","description":"The charge in USD."}}},"ChatRequest":{"type":"object","additionalProperties":true,"allOf":[{"anyOf":[{"required":["model"]},{"required":["models"]}]},{"anyOf":[{"required":["messages"]},{"required":["prompt"]}]}],"properties":{"model":{"type":"string","description":"Model id, author/slug, optionally with :floor or :nitro.","example":"openai/gpt-5.6-luna"},"models":{"type":"array","items":{"type":"string"},"description":"Fallback model ids tried after model."},"provider":{"$ref":"#/components/schemas/ProviderPreferences"},"stream":{"type":"boolean"},"user":{"type":"string","description":"Your end user's id; stored as external_user on the generation."},"plugins":{"type":"null","description":"Not supported: any value other than null returns 400."},"transforms":{"type":"null","description":"Not supported: any value other than null returns 400."},"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string"},"content":{}},"required":["role"]}},"prompt":{"type":"string","description":"Accepted in place of messages."},"max_tokens":{"type":"integer"},"tools":{"type":"array","items":{"type":"object"}},"tool_choice":{},"response_format":{"type":"object"},"reasoning":{"type":"object","properties":{"effort":{"type":"string"},"max_tokens":{"type":"integer"},"exclude":{"type":"boolean"}}}},"example":{"model":"openai/gpt-5.6-luna","messages":[{"role":"user","content":"Say hello in five words."}],"max_tokens":32}},"ChatCompletion":{"type":"object","properties":{"id":{"type":"string","description":"The generation id."},"object":{"const":"chat.completion"},"created":{"type":"integer"},"model":{"type":"string"},"provider":{"type":"string"},"choices":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"finish_reason":{"type":["string","null"]},"message":{"type":"object","properties":{"role":{"type":"string"},"content":{"type":["string","null"]},"tool_calls":{"type":"array","items":{"type":"object"}}}}}}},"usage":{"$ref":"#/components/schemas/Usage"}}},"CompletionRequest":{"type":"object","additionalProperties":true,"allOf":[{"anyOf":[{"required":["model"]},{"required":["models"]}]},{"anyOf":[{"required":["prompt"]},{"required":["messages"]}]}],"properties":{"model":{"type":"string","description":"Model id, author/slug, optionally with :floor or :nitro.","example":"openai/gpt-5.6-luna"},"models":{"type":"array","items":{"type":"string"},"description":"Fallback model ids tried after model."},"provider":{"$ref":"#/components/schemas/ProviderPreferences"},"stream":{"type":"boolean"},"user":{"type":"string","description":"Your end user's id; stored as external_user on the generation."},"plugins":{"type":"null","description":"Not supported: any value other than null returns 400."},"transforms":{"type":"null","description":"Not supported: any value other than null returns 400."},"prompt":{"type":"string"},"messages":{"type":"array","items":{"type":"object"},"description":"Accepted in place of prompt."},"max_tokens":{"type":"integer"}}},"TextCompletion":{"type":"object","properties":{"id":{"type":"string"},"object":{"const":"text_completion"},"model":{"type":"string"},"choices":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"text":{"type":"string"},"finish_reason":{"type":["string","null"]}}}},"usage":{"$ref":"#/components/schemas/Usage"}}},"MessagesRequest":{"type":"object","additionalProperties":true,"required":["messages","max_tokens"],"allOf":[{"anyOf":[{"required":["model"]},{"required":["models"]}]},{"anyOf":[{"required":["messages"]}]}],"properties":{"model":{"type":"string","description":"Model id, author/slug, optionally with :floor or :nitro.","example":"openai/gpt-5.6-luna"},"models":{"type":"array","items":{"type":"string"},"description":"Fallback model ids tried after model."},"provider":{"$ref":"#/components/schemas/ProviderPreferences"},"stream":{"type":"boolean"},"user":{"type":"string","description":"Your end user's id; stored as external_user on the generation."},"plugins":{"type":"null","description":"Not supported: any value other than null returns 400."},"transforms":{"type":"null","description":"Not supported: any value other than null returns 400."},"messages":{"type":"array","items":{"type":"object"}},"max_tokens":{"type":"integer"},"system":{},"tools":{"type":"array","items":{"type":"object"}},"thinking":{"type":"object"}}},"Message":{"type":"object","properties":{"id":{"type":"string","description":"A msg_ id; the generation id is in X-Generation-Id."},"type":{"const":"message"},"role":{"const":"assistant"},"model":{"type":"string"},"content":{"type":"array","items":{"type":"object"}},"stop_reason":{"type":["string","null"]},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"cost":{"type":"number"}}}}},"ResponsesRequest":{"type":"object","additionalProperties":true,"allOf":[{"anyOf":[{"required":["model"]},{"required":["models"]}]},{"anyOf":[{"required":["input"]}]}],"properties":{"model":{"type":"string","description":"Model id, author/slug, optionally with :floor or :nitro.","example":"openai/gpt-5.6-luna"},"models":{"type":"array","items":{"type":"string"},"description":"Fallback model ids tried after model."},"provider":{"$ref":"#/components/schemas/ProviderPreferences"},"stream":{"type":"boolean"},"user":{"type":"string","description":"Your end user's id; stored as external_user on the generation."},"plugins":{"type":"null","description":"Not supported: any value other than null returns 400."},"transforms":{"type":"null","description":"Not supported: any value other than null returns 400."},"input":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"object"}}]},"instructions":{"type":"string"},"tools":{"type":"array","items":{"type":"object"},"description":"Only function tools unless a host serves Responses natively."},"previous_response_id":{"type":"string","description":"Only on a host that serves Responses natively."}}},"Response":{"type":"object","properties":{"id":{"type":"string"},"object":{"const":"response"},"model":{"type":"string"},"status":{"type":"string"},"output":{"type":"array","items":{"type":"object"}},"usage":{"type":"object","properties":{"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"cost":{"type":"number"}}}}},"Model":{"type":"object","description":"Prices are USD per token as decimal strings, at our price.","properties":{"id":{"type":"string","example":"openai/gpt-5.6-luna"},"name":{"type":"string"},"created":{"type":"integer"},"context_length":{"type":"integer"},"architecture":{"type":"object","properties":{"input_modalities":{"type":"array","items":{"type":"string"}},"output_modalities":{"type":"array","items":{"type":"string"}}}},"pricing":{"type":"object","properties":{"prompt":{"type":"string"},"completion":{"type":"string"},"input_cache_read":{"type":"string"},"input_cache_write":{"type":"string"}}},"supported_parameters":{"type":"array","items":{"type":"string"}},"links":{"type":"object","properties":{"details":{"type":"string"}}}}},"ModelList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Model"}},"total_count":{"type":"integer"},"links":{"type":"object","properties":{"next":{"type":"null"}}}}},"ModelEndpoints":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"endpoints":{"type":"array","items":{"type":"object","properties":{"provider_name":{"type":"string"},"tag":{"type":"string"},"context_length":{"type":"integer"},"pricing":{"type":"object"},"quantization":{"type":"string"},"supported_parameters":{"type":"array","items":{"type":"string"}},"uptime_last_30m":{"type":["number","null"],"description":"Share of non-5xx answers; null with no requests in the window."},"latency_last_30m":{"type":["object","null"]},"throughput_last_30m":{"type":["object","null"]}}}}}}}},"Generation":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"model":{"type":"string"},"provider_name":{"type":"string"},"streamed":{"type":"boolean"},"cancelled":{"type":"boolean"},"latency":{"type":"integer","description":"Milliseconds to first byte."},"generation_time":{"type":"integer"},"tokens_prompt":{"type":"integer"},"tokens_completion":{"type":"integer"},"native_tokens_reasoning":{"type":"integer"},"native_tokens_cached":{"type":"integer"},"finish_reason":{"type":["string","null"]},"total_cost":{"type":"number"},"usage":{"type":"number"},"external_user":{"type":["string","null"]},"provider_responses":{"type":"array","items":{"type":"object"}}}}}},"Credits":{"type":"object","properties":{"data":{"type":"object","properties":{"total_credits":{"type":"number"},"total_usage":{"type":"number"}},"required":["total_credits","total_usage"]}}},"KeyInfo":{"type":"object","properties":{"data":{"type":"object","properties":{"label":{"type":"string","example":"sk-pg-v1...3fa"},"limit":{"type":["number","null"]},"limit_reset":{"type":["string","null"]},"limit_remaining":{"type":["number","null"]},"usage":{"type":"number"},"usage_daily":{"type":"number"},"usage_weekly":{"type":"number"},"usage_monthly":{"type":"number"},"is_free_tier":{"const":false},"is_management_key":{"const":false},"budgets":{"type":"array","items":{"type":"object"}}}}}}}}}