DEV Community

Cover image for A Practical Guide to the OpenAI Responses API with Python
Germey
Germey

Posted on Originally published at platform.acedata.cloud

A Practical Guide to the OpenAI Responses API with Python

If you are building an AI feature today, the hard part is rarely “send one prompt and print one answer”; it is handling messages, streaming, usage data, and multi-turn context cleanly.

This guide walks through the OpenAI Responses API as exposed through Ace Data Cloud, using only the fields and examples from the public integration document. The goal is simple: make a minimal Python call, understand the response shape, then turn on streaming and multi-turn input without changing the mental model.

What you can do

The Responses API creates model responses from text or image input. The document describes a unified endpoint:

POST https://api.acedata.cloud/openai/responses
Enter fullscreen mode Exit fullscreen mode

Requests use JSON and bearer-token authentication:

authorization: Bearer {token}
content-type: application/json
accept: application/json
Enter fullscreen mode Exit fullscreen mode

At minimum, the request needs:

  • authorization: selected in the platform UI or passed as a bearer token in code
  • model: for example, gpt-4.1
  • input: an array of messages, where each message has role and content

The documented message roles are user, assistant, and system. Common optional parameters include max_tokens, temperature, n, response_format, tools, and background. For real applications, the most immediately useful optional field is often stream, because it lets a UI render output progressively instead of waiting for the full response.

How it works

Think of the API as a response object factory. You send a model plus structured input, and it returns a response object with fields such as:

  • id: the generated response task ID
  • status: for example, completed or in_progress
  • model: the model used for the response
  • output: the assistant message content
  • usage: token statistics for the request and response

A completed response in the document includes an output array. Inside it, a message item contains content, and the text itself appears under content[].text with type output_text.

That structure is useful because your application does not have to scrape plain text. You can store the full response object for debugging, read usage.total_tokens for observability, and extract only the assistant text for display.

Make the smallest Python call

Here is the basic Python shape from the documentation, adapted to use a placeholder token:

import requests

url = "https://api.acedata.cloud/openai/responses"

headers = {
    "accept": "application/json",
    "authorization": "Bearer {token}",
    "content-type": "application/json"
}

payload = {
    "model": "gpt-4.1",
    "input": [
        {"role": "user", "content": "Hello"}
    ]
}

response = requests.post(url, json=payload, headers=headers)
print(response.text)
Enter fullscreen mode Exit fullscreen mode

The important thing is the shape of input. Even for one user message, it is still an array. That makes the jump to multi-turn conversation straightforward later.

A typical completed response includes fields like this:

{
  "object": "response",
  "status": "completed",
  "model": "gpt-4.1",
  "output": [
    {
      "type": "message",
      "status": "completed",
      "content": [
        {
          "type": "output_text",
          "text": "Hello! How can I help you today?"
        }
      ],
      "role": "assistant"
    }
  ],
  "usage": {
    "input_tokens": 8,
    "output_tokens": 10,
    "total_tokens": 18
  }
}
Enter fullscreen mode Exit fullscreen mode

For a production app, I would avoid assuming output[0] is always present. Check status, check error, then look for message items and output_text content.

Add streaming for web interfaces

For a chat UI, streaming makes the experience feel much better. The document enables this by adding stream: True to the payload:

import requests

url = "https://api.acedata.cloud/openai/responses"

headers = {
    "accept": "application/json",
    "authorization": "Bearer {token}",
    "content-type": "application/json"
}

payload = {
    "model": "gpt-4.1",
    "input": [{"role": "user", "content": "Hello"}],
    "stream": True
}

response = requests.post(url, json=payload, headers=headers)
print(response.text)
Enter fullscreen mode Exit fullscreen mode

The streaming response returns data: lines. The document shows event types such as response.created, response.in_progress, response.output_item.added, response.output_text.delta, response.output_text.done, and response.completed.

The key event for rendering incremental text is:

{
  "type": "response.output_text.delta",
  "delta": "Hello"
}
Enter fullscreen mode Exit fullscreen mode

The end condition is also explicit: when the event type is response.completed, the stream has finished. That gives you a clean loop for frontend or backend streaming handlers:

  1. Read each data: line.
  2. Parse the JSON payload.
  3. Append delta values from response.output_text.delta.
  4. Stop when type becomes response.completed.

Keep multi-turn context explicit

Multi-turn dialogue is handled by sending multiple messages in the same input array. The document’s example uses a previous user message, an assistant reply, and then a follow-up user question:

payload = {
    "model": "gpt-4.1",
    "input": [
        {"role": "user", "content": "Hello"},
        {"role": "assistant", "content": "Hello! How can I help you today? 😊"},
        {"role": "user", "content": "What did I just say?"}
    ]
}
Enter fullscreen mode Exit fullscreen mode

This is simple, but it is also a good architectural constraint. Your application owns the conversation state. You decide which previous messages to include, how much history to keep, and whether to summarize older turns before sending them again.

Practical implementation notes

A few details are worth making explicit before wiring this into an app:

  • Keep the bearer token on the server side. Do not expose it in browser JavaScript.
  • Log id, status, model, and usage for debugging and cost visibility.
  • Use temperature only when you actually want more variation; the documented range is 0-2.
  • Use max_tokens when you need predictable response length.
  • Treat streaming as a transport concern. The request shape stays almost the same; only stream changes.

The nice thing about this API shape is that it scales from a “Hello” script to a real chat interface without introducing a second abstraction. You start with model and input, then add stream, multi-turn messages, or optional fields as the product needs them.

Full reference: OpenAI Responses API Integration Guide.

Top comments (0)