---
title: "OpenAI-compatible chat completions with policy enforcement"
method: POST
path: "/v1/chat/completions"
tags: ["OpenAI Compatible"]
---

# OpenAI-compatible chat completions with policy enforcement

`POST /v1/chat/completions`

## Request

- Base URL: `https://agent.getaxonflow.com`
- URL: `https://agent.getaxonflow.com/v1/chat/completions`
- Auth: none declared. Required headers: `X-Provider-Key`
- TypeScript: <https://skmtc.dev/getaxonflow/apis/axonflow-agent-api/docs/v1/chat/completions/post.ts> (a function with typed inputs; its response is checked against the schema)

Accepts a standard OpenAI Chat Completions request, decides it with
the ADR-065 decision plane (PRD v11 §1.1; #4092) - the shared policy
engine's detectors are its input - forwards an allowed request to the
upstream provider, records audit (tokens, cost, latency, policy
decision), and returns an OpenAI-compatible response.

The route carries no per-user identity, so every request is decided
for its client credential (`Client`). OpenAI's `user` request member
is NOT honoured as an identity: it is free text the caller chooses,
and a principal is never taken from it.

The caller passes their upstream provider API key via the
`X-Provider-Key` header. AxonFlow auth (Basic Auth or community
mode) is handled by the same `apiAuthMiddleware` as all other
agent endpoints.

Streaming (`stream: true`) is not supported in this release and
returns HTTP 400 with a clear error.

## Headers

- `X-Provider-Key` string, required
- `traceparent` string

## Request body

- ChatCompletionRequest
  - `model` string, required: ID of the model to use (e.g. gpt-4o, gpt-4o-mini).
  - `messages` object[], required
    - `role` 'system' | 'user' | 'assistant' | 'tool', required
    - `content` unknown, required
    - `name` string
    - `tool_calls` object[]
    - `tool_call_id` string
  - `temperature` number
  - `top_p` number
  - `max_tokens` integer
  - `max_completion_tokens` integer
  - `stream` boolean: Must be false or omitted. Streaming is not supported in this release; setting stream=true returns HTTP 400.
  - `stop` unknown
  - `presence_penalty` number
  - `frequency_penalty` number
  - `user` string
  - `response_format` object
  - `seed` integer
  - `tools` object[]
  - `tool_choice` unknown

## Response `200`

Successful completion

- ChatCompletionResponse
  - `id` string, required: Unique identifier for the completion.
  - `object` 'chat.completion', required
  - `created` integer, required: Unix timestamp of creation.
  - `model` string, required: Model used for the completion.
  - `choices` object[], required
    - `index` integer
    - `message` object
      - `role` string
      - `content` string, nullable
      - `tool_calls` object[]
    - `finish_reason` 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'null', nullable
  - `usage` object
    - `prompt_tokens` integer
    - `completion_tokens` integer
    - `total_tokens` integer
  - `system_fingerprint` string

## Other responses

- `400`: Request validation error or policy denial. Policy denials use `type: "policy_violation"` and `code: "policy_denied"`. The OpenAI SDK parses this as `openai.BadRequestError`.
- `401`: Missing or invalid authentication. Handler-written 401s use the `{success, error}` envelope; 401s written by the auth middleware use the `{"error": {"code", "message"}}` envelope (JSONError).
- `503`: No engine could decide the request: no enforcer is wired, the organization's policy document cannot be read or activated, or the identity plane cannot establish the request's subject. The request is refused, never forwarded ungoverned, and the body is an OpenAI error.

---

[API](https://skmtc.dev/getaxonflow/apis/axonflow-agent-api.md) - [All operations](https://skmtc.dev/getaxonflow/apis/axonflow-agent-api/llms.txt) - [OpenAPI document](https://skmtc.dev/getaxonflow/apis/axonflow-agent-api/revisions/34d30fcb7fa1?raw)
