Base URLs & request surfaces

The gateway serves three request surfaces, because the clients worth firewalling do not agree on one. Which surface you use is decided by your client, not by you — and it determines the shape of your base URL.

Warning The OpenAI and Anthropic SDKs disagree about /v1. The OpenAI SDK expects it in the base URL. The Anthropic SDK appends it itself, so its base URL must stop at the organisation. This trips up nearly everyone who configures by hand — vulnetix ai-firewall install gets it right for you.

The two shapes

Your clientBase URL
OpenAI SDKs, LangChain, LlamaIndex, Codex, curlhttps://guardrails.vulnetix.com/{provider}/{orgUuid}/v1
Anthropic SDKs, Claude Code, Claude Desktophttps://guardrails.vulnetix.com/anthropic/{orgUuid}  — no /v1

{provider} is the provider slug (openai, anthropic, openrouter, groq, … — see the provider catalog). {orgUuid} is your organisation UUID, from the dashboard.

Both are URL components on purpose: the entire configuration fits into the two knobs every LLM client supports — base_url and api_key — so no client needs to send a custom header.

The three surfaces

SurfaceRouteSpoken by
chatPOST /v1/chat/completionsOpenAI SDKs, LangChain, Cursor, Continue, Aider, curl — most things
responsesPOST /v1/responsesCodex CLI (its config accepts no other wire_api)
messagesPOST /v1/messagesAnthropic SDKs, Claude Code, Claude Desktop

Guardrails apply identically across all three. A rule you write once covers a curl, a Codex turn, and a Claude Code tool result alike — you never write a policy per surface.

Not every provider serves every surface. Which ones a provider serves is part of its catalog entry:

ProviderSurfaces
openaichat, responses
anthropicmessages
everything elsechat

When you get it wrong

Asking a provider for a surface it does not serve is a 404, and the message tells you what to use instead. This is deliberate: a misconfigured base URL should not surface as a confusing 401 or a timeout.

{
  "type": "error",
  "error": {
    "type": "not_found_error",
    "code": "unsupported_api",
    "message": "provider groq does not support the Anthropic Messages API (POST /v1/messages). Use POST /v1/chat/completions for groq, or point your Anthropic client at a provider that serves the Messages API: https://guardrails.vulnetix.com/anthropic/{orgUuid} (note: no /v1 suffix — the Anthropic SDK appends it)"
  }
}

The CLI catches the same class of mistake locally, before you ever send a request — it is the wire_unsupported check in vulnetix ai-firewall status.

Errors come back in your client’s dialect

The error envelope follows the route you called, never the provider. An Anthropic SDK that hits /v1/messages gets an Anthropic-shaped error even when the failure is “this provider is not an Anthropic provider” — because that is the only shape it can render. Given an OpenAI-shaped body, Claude Code would print a bare API Error: 403 with no detail, and every guardrail block would be unreadable.

The full taxonomy, in both shapes, is in the error reference.

Model names pass through untouched

The gateway does not rewrite, prefix, or normalise the model you send. Use whatever naming the provider itself uses:

ProviderModel string
openaigpt-4o-mini
openrouteropenai/gpt-4o-mini
anthropicclaude-sonnet-5

Getting this wrong produces the provider’s own “unknown model” error, relayed verbatim — not one of ours.