Skip to content

Responses (OpenAI)

OpenAI Responses-format inbound adapter. OpenAI's Codex CLI only speaks /v1/responses, so this endpoint lets Codex and the Responses SDK attach.

OpenAI's Codex CLI only speaks the /v1/responses format. PleumRouter provides an inbound adapter that accepts this format and translates it into internal model calls, so you can attach Codex CLI (and the OpenAI Responses SDK) to PleumRouter as-is.

POST/v1/responses

Connecting#

Set the base URL to https://apirouter.pleum.ai/v1 and the API key to your plm_ key. In Codex, set wire_api = "responses" so it calls this endpoint.

connect
export OPENAI_BASE_URL="https://apirouter.pleum.ai/v1"
export OPENAI_API_KEY="plm_..."
responses.ts

OpenAI Responses API (Codex)

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: "plm_xxxxxxxxxxxxxxxx",
  baseURL: "https://apirouter.pleum.ai/v1",
});

const response = await client.responses.create({
  model: "gpt-4.1",
  input: "Why is the sky blue?",
});

console.log(response.output_text);
POST /v1/responses/{request_id}/feedback is a separate routing feedback endpoint (JWT), not Responses create.

Request body#

ParameterTypeRequiredDescription
modelstringRequiredModel ID. See the full list at GET /v1/models.
inputstring | arrayRequiredA string, or an array of items (message / function_call / function_call_output).
instructionsstringOptionalPrepended as a system message.
max_output_tokensintegerOptionalDefault 4096. Maps to the internal max_tokens.
temperaturenumberOptionalSampling temperature.
top_pnumberOptionalNucleus sampling.
streambooleanOptionalIf true, returns a Responses SSE streaming response.
toolsarrayOptionalResponses flat function tools ({type:"function", name, description, parameters}) are converted. Non-function tools (e.g. web_search) are silently dropped.
tool_choicestring | objectOptionalString auto | none | required, or {type:"function", name}.
parallel_tool_callsbooleanOptionalWhether parallel tool calls are allowed.
metadataobjectOptionalArbitrary key-value metadata.
request
curl https://apirouter.pleum.ai/v1/responses \
  -H "Authorization: Bearer $PLEUM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4.1",
    "instructions": "You are a helpful assistant.",
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": "Hello"
      }
    ],
    "max_output_tokens": 4096,
    "stream": false
  }'

Response#

A non-streaming response returns the assistant message in the output array. Each message's content consists of output_text parts, and usage includes input_tokens / output_tokens / total_tokens. Cost is returned in the X-Cost-Krw / X-Cost-Usd response headers, not the body. Extra fields Codex sends (reasoning, text, store, previous_response_id, include, prompt_cache_key) are accepted but ignored.

200 OK
{
  "id": "resp_gpt-4.1-841ms",
  "object": "response",
  "created_at": 1735689600,
  "status": "completed",
  "model": "gpt-4.1",
  "output": [
    {
      "id": "msg_abc123",
      "type": "message",
      "status": "completed",
      "role": "assistant",
      "content": [
        {"type": "output_text", "text": "Hi!", "annotations": []}
      ]
    }
  ],
  "usage": {
    "input_tokens": 12,
    "output_tokens": 5,
    "total_tokens": 17
  }
}

Streaming#

With stream: true, Responses SSE events are sent — response.createdresponse.in_progress output_item.added / content_part.added / output_text.deltaoutput_text.done / output_item.doneresponse.completed with the full usage. Codex reads completed items from output_item.done and determines termination from response.completed.

Responses SSE stream
data: {"type":"response.created","response":{"id":"resp_abc","status":"in_progress"}}

data: {"type":"response.in_progress","response":{"id":"resp_abc"}}

data: {"type":"output_item.added","item":{"id":"msg_abc","type":"message","role":"assistant"}}

data: {"type":"content_part.added","item_id":"msg_abc","part":{"type":"output_text","text":""}}

data: {"type":"response.output_text.delta","item_id":"msg_abc","delta":"Hi"}

data: {"type":"response.output_text.delta","item_id":"msg_abc","delta":"!"}

data: {"type":"response.output_text.done","item_id":"msg_abc","text":"Hi!"}

data: {"type":"output_item.done","item":{"id":"msg_abc","type":"message","role":"assistant","content":[{"type":"output_text","text":"Hi!"}]}}

data: {"type":"response.completed","response":{"id":"resp_abc","status":"completed","usage":{"input_tokens":12,"output_tokens":5,"total_tokens":17}}}
Built-in tools like web_search are not forwarded and are silently dropped. Only {type:"function"} tools are converted and passed to the model.