Safeguard Docs
API Platform (Console)

Chat completions

POST /chat/completions reference: every request field the gateway reads or passes on, the response fields, cost, and the v1 limits.

POST https://api.safeguard.sh/gpt/v1/chat/completions

The request and response follow OpenAI's Chat Completions format. Safeguard reads a few fields itself, passes a fixed set of optional fields to the provider, and ignores everything else.

v1 limits

Text only: a message part that is not text is refused. n must be 1. Your own models (custom:<id>) are refused with an API key; the gateway accepts them only from the Console Workbench, which cannot pick them yet. The API Platform is switched on per workspace by Safeguard, and while it is in early access it answers 403 gateway_disabled where it is off.

Request

Send JSON with Content-Type: application/json and your key in Authorization: Bearer <key>. The body can be up to 8 MiB; a larger body is refused with 413 request_too_large.

Fields Safeguard reads

FieldTypeRules
modelstring, requiredA model id from GET /models.
messagesarray, required1 to 2,000 messages. See Messages.
max_completion_tokensinteger1 to 1,000,000. If both are sent, max_completion_tokens wins over max_tokens.
max_tokensinteger1 to 1,000,000.
temperaturenumber0 to 2.
top_pnumber0 to 1.
stopstring or arrayA string, or up to four strings.
streambooleantrue returns server-sent events. See Streaming.
stream_options.include_usagebooleanWith stream: true, adds a final chunk carrying usage.
nintegerOnly 1. Any other value is refused with 400 unsupported_parameter.
userstringAccepted and dropped. It is never sent to the provider.
providerobjectSafeguard's routing options. See Routing options.

The output token cap sent to the provider is the value you set, lowered to the model's max_output_tokens when the catalog states one. If you set none, the cap is 4,096 tokens or the model's maximum, whichever is lower.

Fields passed to the provider

These are forwarded unchanged when present. The gateway does not check their values; the provider does.

FieldNotes
tools, tool_choiceFunction calling. Whether a model supports tools is up to the model.
parallel_tool_calls
response_formatJSON mode or structured output, where the model supports it.
seed
presence_penalty, frequency_penalty

For Anthropic models, only temperature, tools and tool_choice from the two tables are sent with the messages and the token cap; top_p, stop, response_format, seed, the penalties and parallel_tool_calls are not. When you set no temperature, the provider's own default applies.

Any field not listed on this page is ignored and not forwarded.

Messages

Each message is an object with a role and, usually, content.

  • role is one of system, developer, user, assistant or tool. The gateway accepts all five; whether a model accepts developer or tool messages is up to its provider.
  • content is a string, null, or an array of text parts such as {"type": "text", "text": "..."}. A part of any other type, such as an image or audio, is refused with 400 unsupported_parameter.
  • name, tool_calls and tool_call_id are kept. Other keys on a message are dropped.

Routing options

provider is a Safeguard extension:

"provider": { "allow_fallbacks": true, "zdr": true }
FieldMeaning
allow_fallbackstrue lets the gateway retry once and then try a listed fallback model of the same family when the provider fails. false turns that off. When absent, the workspace setting applies, and it is off unless a tenant admin or super admin turns it on. See Reliability and fallbacks.
zdrtrue routes only to models offered with zero data retention. When the workspace requires zero data retention, every request is routed that way and a request cannot turn it off. See Zero data retention.

Fallbacks never leave the model family, and never go to the models Safeguard uses for its own platform features.

Where routing is switched on for your workspace, provider also takes order, only, ignore and sort, and the request can list more models in models. Where it is not, those fields are refused with 400 unsupported_parameter.

When a provider rejects a parameter

Providers do not all accept the same parameters. If a provider rejects the token limit's name, the gateway switches between max_tokens and max_completion_tokens and sends the request again. If it rejects another optional parameter as unsupported for the model, such as a temperature the model does not allow, the gateway drops that parameter and sends the request again. These repeats go to the same provider and are not fallbacks.

Examples

A basic request

curl https://api.safeguard.sh/gpt/v1/chat/completions \
  -H "Authorization: Bearer $SAFEGUARD_INFERENCE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_ID",
    "messages": [
      {"role": "system", "content": "Answer in one short paragraph."},
      {"role": "user", "content": "What does reachability analysis add to a vulnerability scan?"}
    ],
    "max_completion_tokens": 300,
    "temperature": 0.2
  }'

Calling a tool

The gateway passes tools and tool_choice to the provider and returns the provider's tool_calls in the message.

curl https://api.safeguard.sh/gpt/v1/chat/completions \
  -H "Authorization: Bearer $SAFEGUARD_INFERENCE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_ID",
    "messages": [{"role": "user", "content": "Is lodash 4.17.20 affected by a known vulnerability?"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "lookup_package",
        "description": "Look up known vulnerabilities for a package version.",
        "parameters": {
          "type": "object",
          "properties": {
            "ecosystem": {"type": "string"},
            "name": {"type": "string"},
            "version": {"type": "string"}
          },
          "required": ["ecosystem", "name", "version"]
        }
      }
    }],
    "tool_choice": "auto"
  }'

To continue the conversation, send the assistant message with its tool_calls, then a tool message with the matching tool_call_id and your function's result as content.

Requiring zero data retention and allowing fallbacks

provider is not an OpenAI parameter, so the OpenAI SDKs send it through extra_body (Python) or as an extra field (Node.js).

curl https://api.safeguard.sh/gpt/v1/chat/completions \
  -H "Authorization: Bearer $SAFEGUARD_INFERENCE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_ID",
    "messages": [{"role": "user", "content": "Summarise this incident report in three bullet points: ..."}],
    "provider": {"zdr": true, "allow_fallbacks": true}
  }'

Response

{
  "id": "gen-6f1c2e0a9b4d4c7e8a1f3b5d7c9e0a2b",
  "object": "chat.completion",
  "created": 1791475000,
  "model": "MODEL_ID",
  "provider": "openai",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Reachability analysis checks whether ..." },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 41,
    "completion_tokens": 120,
    "total_tokens": 161,
    "cost": 0.000521
  }
}

The values above are illustrative.

FieldMeaning
idThe request id: gen- and 32 hexadecimal characters. Safeguard logs the request under it, and the X-Generation-Id response header carries the same id.
objectchat.completion.
createdUnix time in seconds.
modelThe model that answered. When a fallback answered, this is the fallback's id.
providerThe route that served the request, such as openai. See Models.
choicesOne choice. message holds role (assistant), content, and any other field the provider returned with a value, such as tool_calls. finish_reason is the provider's, such as stop, length or tool_calls.
usage.prompt_tokens, usage.completion_tokens, usage.total_tokensToken counts as the provider reported them.
usage.costWhat the request cost in US dollars, as a JSON number.
usage.prompt_tokens_details.cached_tokensPresent when the provider reported cached input tokens.
usage.estimatedtrue when the provider reported no usage, so the gateway counted the tokens itself. Absent otherwise.

Cost

For each request the gateway works out:

cost = (input tokens × input price + output tokens × output price) ÷ 1,000,000

with prices in US dollars per million tokens from the catalog, and no markup. When the catalog has a cached-input price, cached input tokens are charged at that price instead of the input price. The result is rounded half up to 8 decimal places.

Before calling the provider, the gateway reserves the most the request could cost and refuses it with 402 if that does not fit your credit or a spend limit. After the call, it charges the actual cost and releases the rest. A request that ends in an error before any output costs nothing. See Limits and Pricing and billing.

Errors

Errors use OpenAI's shape, {"error": {"message", "type", "code", "param"}}. Errors lists every status and code.

On this page