{"openapi":"3.1.0","info":{"title":"Vigil proxy","version":"2026-10-04","description":"Vigil's own surface: the pass-through route and Vigil's errors. Docs: https://www.vigil.wtf/docs"},"servers":[{"url":"https://api.vigil.wtf"}],"paths":{"/{user_id}/{provider}/{path}":{"post":{"operationId":"proxyPOST","summary":"Forward a POST request to the provider","description":"A pass-through: the request is forwarded to the provider named by {provider} with {path} appended, and the provider's response comes back. Bodies are the provider's own.","parameters":[{"name":"user_id","in":"path","required":true,"description":"Your Vigil user id.","schema":{"type":"string","format":"uuid"}},{"name":"provider","in":"path","required":true,"description":"The provider segment.","schema":{"type":"string","enum":["anthropic","bedrock","vertex","openai","google","mistral","xai","fireworks","baseten","cloudflare","groq","together","deepseek","moonshot","cerebras","zai","openrouter"]}},{"name":"path","in":"path","required":true,"description":"The provider's own path, which may contain slashes (e.g. v1/messages).","schema":{"type":"string"}},{"name":"X-Vigil-Key","in":"header","required":true,"description":"Your Vigil API key. Required. Create a key in the dashboard, under Settings → API keys or on the setup page; it is shown once. On providers where the Authorization header is free, you can send it as Authorization: Bearer <key> instead. A request with no key, or a key Vigil does not recognise, is refused with 401; if Vigil cannot check the key in time, with a retryable 503.","schema":{"type":"string"}},{"name":"X-Vigil-Agent","in":"header","required":false,"description":"A label for the agent or app making the call. Calls are grouped by this label on the dashboard, and each label has its own optimisation settings. A call with no label, or an empty one, is untagged: it follows your account default, and the dashboard groups untagged calls by prompt.","schema":{"type":"string"}},{"name":"X-Vigil-Optimise","in":"header","required":false,"description":"off — run no optimisation on this request. Only the value off has an effect (it is read as a comma-separated list, so a repeated header still works). It can only switch optimisation off, never on. The call is still logged.","schema":{"type":"string"}},{"name":"X-Vigil-Skip","in":"header","required":false,"description":"A comma-separated list of optimisations to switch off for this request, e.g. prompt_cache. Up to 32 names, read from the first 256 characters; unknown names are ignored. Like X-Vigil-Optimise, it can only switch things off.","schema":{"type":"string"}}],"responses":{"400":{"description":"malformed_path, invalid_user_id, unknown_provider, missing_path, invalid_bedrock_route, invalid_vertex_route, vertex_regional_unavailable","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"401":{"description":"missing_api_key, invalid_api_key, key_user_mismatch","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"500":{"description":"vigil_internal_error","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"502":{"description":"vigil_upstream_unreachable, vigil_upstream_body_unreadable","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"503":{"description":"vigil_auth_unavailable","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"529":{"description":"vigil_upstream_timeout","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"default":{"description":"The provider's response, passed through, with Vigil's response headers added.","headers":{"x-vigil-request-id":{"description":"The id Vigil gave this request. On every response — streamed, refused or failed. Paste it into the search on the dashboard's Calls page to find the call, what each optimisation did to it, and its saving — or why Vigil refused it.","schema":{"type":"string"}},"x-vigil-techniques":{"description":"Which optimisations ran in Shadow or On, and what each did. Non-streamed responses only. A structured-field dictionary, for example prompt_cache=on;outcome=acted. Absent when none ran.","schema":{"type":"string"}},"x-vigil-saved-usd":{"description":"The measured saving on this call, in US dollars. Non-streamed responses only. A signed decimal, negative when a cache write did not pay off. Never an estimate, and absent rather than 0 when nothing was measured. A streamed call gets only x-vigil-request-id; look its saving up by that id.","schema":{"type":"string"}}}}}},"get":{"operationId":"proxyGET","summary":"Forward a GET request to the provider","description":"A pass-through: the request is forwarded to the provider named by {provider} with {path} appended, and the provider's response comes back. Bodies are the provider's own.","parameters":[{"name":"user_id","in":"path","required":true,"description":"Your Vigil user id.","schema":{"type":"string","format":"uuid"}},{"name":"provider","in":"path","required":true,"description":"The provider segment.","schema":{"type":"string","enum":["anthropic","bedrock","vertex","openai","google","mistral","xai","fireworks","baseten","cloudflare","groq","together","deepseek","moonshot","cerebras","zai","openrouter"]}},{"name":"path","in":"path","required":true,"description":"The provider's own path, which may contain slashes (e.g. v1/messages).","schema":{"type":"string"}},{"name":"X-Vigil-Key","in":"header","required":true,"description":"Your Vigil API key. Required. Create a key in the dashboard, under Settings → API keys or on the setup page; it is shown once. On providers where the Authorization header is free, you can send it as Authorization: Bearer <key> instead. A request with no key, or a key Vigil does not recognise, is refused with 401; if Vigil cannot check the key in time, with a retryable 503.","schema":{"type":"string"}},{"name":"X-Vigil-Agent","in":"header","required":false,"description":"A label for the agent or app making the call. Calls are grouped by this label on the dashboard, and each label has its own optimisation settings. A call with no label, or an empty one, is untagged: it follows your account default, and the dashboard groups untagged calls by prompt.","schema":{"type":"string"}},{"name":"X-Vigil-Optimise","in":"header","required":false,"description":"off — run no optimisation on this request. Only the value off has an effect (it is read as a comma-separated list, so a repeated header still works). It can only switch optimisation off, never on. The call is still logged.","schema":{"type":"string"}},{"name":"X-Vigil-Skip","in":"header","required":false,"description":"A comma-separated list of optimisations to switch off for this request, e.g. prompt_cache. Up to 32 names, read from the first 256 characters; unknown names are ignored. Like X-Vigil-Optimise, it can only switch things off.","schema":{"type":"string"}}],"responses":{"400":{"description":"malformed_path, invalid_user_id, unknown_provider, missing_path, invalid_bedrock_route, invalid_vertex_route, vertex_regional_unavailable","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"401":{"description":"missing_api_key, invalid_api_key, key_user_mismatch","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"500":{"description":"vigil_internal_error","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"502":{"description":"vigil_upstream_unreachable, vigil_upstream_body_unreadable","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"503":{"description":"vigil_auth_unavailable","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"529":{"description":"vigil_upstream_timeout","headers":{"X-Vigil-Error":{"description":"Vigil's machine code, as in error.vigil_error_code.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VigilError"}}}},"default":{"description":"The provider's response, passed through, with Vigil's response headers added.","headers":{"x-vigil-request-id":{"description":"The id Vigil gave this request. On every response — streamed, refused or failed. Paste it into the search on the dashboard's Calls page to find the call, what each optimisation did to it, and its saving — or why Vigil refused it.","schema":{"type":"string"}},"x-vigil-techniques":{"description":"Which optimisations ran in Shadow or On, and what each did. Non-streamed responses only. A structured-field dictionary, for example prompt_cache=on;outcome=acted. Absent when none ran.","schema":{"type":"string"}},"x-vigil-saved-usd":{"description":"The measured saving on this call, in US dollars. Non-streamed responses only. A signed decimal, negative when a cache write did not pay off. Never an estimate, and absent rather than 0 when nothing was measured. A streamed call gets only x-vigil-request-id; look its saving up by that id.","schema":{"type":"string"}}}}}}}},"components":{"schemas":{"VigilError":{"type":"object","required":["type","error"],"properties":{"type":{"const":"error"},"error":{"type":"object","required":["type","message","vigil_error_code"],"properties":{"type":{"type":"string","description":"From Anthropic's error types, so provider SDKs classify and retry it correctly."},"message":{"type":"string","description":"Names Vigil, and says how to fix it."},"vigil_error_code":{"type":"string","enum":["malformed_path","invalid_user_id","unknown_provider","missing_path","invalid_bedrock_route","invalid_vertex_route","vertex_regional_unavailable","missing_api_key","invalid_api_key","key_user_mismatch","vigil_auth_unavailable","vigil_upstream_timeout","vigil_upstream_unreachable","vigil_upstream_body_unreadable","vigil_upstream_unparseable","vigil_internal_error"]}}}}}}}}