# Create Response

`POST https://api.vultrinference.com/v1/responses`

Create an OpenAI-compatible response. `reasoning.effort` maps through the selected model's `reasoning_config` when configured. `reasoning.max_tokens` caps thinking tokens when the model advertises `reasoning.supports_max_tokens: true` in `/v1/models?format=openrouter` (a `max_tokens` property under the `reasoning` parameter in the default list); other models accept the budget without enforcing it. `reasoning.context` and `reasoning.mode` are accepted but ignored. The `:express` model variant derives a budget for models with enforced budget support when no budget is supplied.

**Response shape:** Responses follow OpenAI's Responses API object whichever engine serves the model, with the fields OpenRouter's SDKs require always present: `completed_at` is a unix timestamp once the response has finished, `error` is `null` or `{code, message}`, and `text` is an object. Function call ids start with `call_`, and engine-internal fields (`kv_transfer_params`, `input_messages`, `output_messages`, ...) are removed from the response and from every streamed event.

**Tools:** `function`, `custom` and `namespace` tools, as Codex CLI sends them. A `custom` tool's call is a `custom_tool_call` item whose `input` is the raw text; its `format` grammar is described to the model, not enforced. A call to a tool of a `namespace` is a `function_call` with `namespace` set. Hosted tools (`web_search`, `file_search`, `code_interpreter`, `mcp`, ...) are refused with a 400 naming the type.

**Stored responses:** Nothing is stored. `store` is accepted and ignored. `previous_response_id`, `conversation` and `background: true` are refused with a 400; send the whole conversation in `input`. [`GET`](#operation/get-response) and [`DELETE`](#operation/delete-response) on `/v1/responses/{id}` answer a 404 saying so.

**Context window:** If input plus `max_output_tokens` passes the model's context length, `max_output_tokens` is reduced to fit; if the input alone does not fit the request is a 400 with `metadata.error_type` `context_length_exceeded`.

**Errors:** Errors use OpenRouter's envelope, `{"error": {"code", "message", "type", "metadata": {"error_type"}}}`. A streaming request that fails before the first event gets the real HTTP status and the JSON envelope; one that fails later ends the stream with an `error` event and a `response.failed` event.

## Body (application/json)

- `model` (string): If omitted, the gateway resolves its default model. A `:<variant>` suffix is parsed separately from the model ID; `:express` derives a thinking budget when the model supports enforced budgets and no explicit budget is supplied.
- `input` (string or array of objects, required): Input text or structured input items. A message item's `content` may hold `input_text`, `input_image` and `input_file` parts. An `input_file` (`{"type": "input_file", "filename": "report.pdf", "file_data": "data:application/pdf;base64,..."}`, or `file_url` in place of `file_data`) is converted to text before the model sees it, with the types, limits, token counting, caching and errors described under `chat-content-part`. `file_id` (a file uploaded with `POST /files`) uses its stored text.
- `instructions` (string): A system prompt.
- `max_output_tokens` (integer): Maximum output tokens, including reasoning and visible output. Reduced to fit the model's context window with the input. [default 32768, at least 1]
- `temperature` (number) [range 0–2]
- `top_p` (number) [range 0–1]
- `tools` (array of objects): `function`, `custom` and `namespace` tools. Any other `type` (hosted tools such as `web_search`) is refused with a 400 naming it.
  - `type` (string, required) [function, custom, namespace]
  - `name` (string, required)
  - `description` (string)
  - `parameters` (object): A `function` tool's arguments, as a JSON schema.
  - `strict` (boolean)
  - `format` (object): A `custom` tool's input: `{"type": "text"}` (the default) or `{"type": "grammar", "syntax": "lark" or "regex", "definition": "..."}`. The grammar is described to the model; the engine does not enforce it.
  - `tools` (array of objects): A `namespace` tool's `function` tools. A call to one comes back as a `function_call` with `namespace` set.
- `tool_choice` (string or object): `none`, `auto`, `required`, or a specific `function` or `custom` tool. Anything but `none` needs `tools`.
- `reasoning` (object): Reasoning controls. Configured models map effort through their database profile. Models advertising `reasoning.supports_max_tokens: true` in `/v1/models?format=openrouter` (a `max_tokens` property under the `reasoning` parameter in the default list) enforce the budget; other models accept it without enforcing it.
  - `effort` (string) [ultra, max, xhigh, high, medium, low, minimal, none]
  - `enabled` (boolean): When false, sets effort to `none`.
  - `summary` (string): Accepted but not supported by the current engines. [auto, concise, detailed]
  - `max_tokens` (integer): Thinking-token budget. Must be below the effective completion limit so the model has room to answer. Ignored when thinking is disabled or a final assistant message is being continued. [at least 1]
- `store` (boolean): Accepted and ignored. Nothing is stored, whatever the value.
- `previous_response_id` (string or null): Refused with a 400 unless null. Responses are not stored; send the whole conversation in `input`.
- `conversation` (any): Refused with a 400. Conversations are not stored.
- `background` (boolean): `true` is refused with a 400. A background response would have to be stored to be retrieved.
- `stream` (boolean)

## Responses

- `200`: OK (response-create-response-payload)
- `400`: Bad Request, including an unsupported tool type, previous_response_id, and context_length_exceeded (error-payload)
- `401`: The API key is missing, unknown or not active. Send it as Authorization: Bearer <key>. (error-payload)
- `404`: Unknown model (error-payload)
- `429`: Rate limit exceeded (error-payload)
- `502`: The model could not be reached (error-payload)
- `504`: The model timed out (error-payload)

## Example

```bash
curl https://api.vultrinference.com/v1/responses \
  -H "Authorization: Bearer $VULTR_INFERENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash",
    "instructions": "Answer in one sentence.",
    "input": "Why is the sky blue?",
    "max_output_tokens": 512
  }'
```

```python
import os
import requests

response = requests.post(
    "https://api.vultrinference.com/v1/responses",
    headers={"Authorization": f"Bearer {os.environ['VULTR_INFERENCE_API_KEY']}"},
    json={
        "model": "deepseek-v4.1-flash",
        "instructions": "Answer in one sentence.",
        "input": "Why is the sky blue?",
        "max_output_tokens": 512,
    },
)
print(response.json())
```

```javascript
const response = await fetch("https://api.vultrinference.com/v1/responses", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.VULTR_INFERENCE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "deepseek-v4.1-flash",
    "instructions": "Answer in one sentence.",
    "input": "Why is the sky blue?",
    "max_output_tokens": 512
  }),
});
console.log(await response.json());
```
