> ## Documentation Index
> Fetch the complete documentation index at: https://nusaai-edit.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Responses vs. Chat Completions

> > Understanding the practical differences when using the OpenAI SDK with our endpoints.

When you use an official OpenAI SDK like [`openai-python`](https://pypi.org/project/openai/) or [`openai-node`](https://www.npmjs.com/package/openai)) with Neosantara AI's `base_url`, the library maps its methods to our API endpoints. While both [`v1/responses`](api-reference/response) and [`v1/chat/completions`](api-reference/chat) can hold a conversation, how you interact with them through the SDK is fundamentally different.

For new projects, we strongly recommend using the **`client.responses.create()`** method.

<Note>
  If you want use `Function Calling` please use the [v1/chat/completions](en/tools-overview) instead for working with function

  we will fixed in `v1/response` soon for supported function calling
</Note>

***

## Key SDK Differences

### 1. The Method You Call

The most direct difference is the method you invoke on the client object.

* **Chat Completions** uses the nested `chat.completions.create()` method.
* **Responses** uses the top-level `responses.create()` method, reflecting its status as a primary, modern API.

<CodeGroup>
  ```python completions.py icon="python" theme={null}
  # Chat Completions SDK Usage
  completion = client.chat.completions.create(
      model="nusantara-base",
      messages=[{"role": "user", "content": "Hello!"}]
  )
  ```

  ```python response.py icon="python" theme={null}
  # Responses SDK Usage
  response = client.responses.create(
      model="nusantara-base",
      input="Hello!"
  )
  ```
</CodeGroup>

**Diff Comparison:**

```python icon="code" lines theme={null}
# SDK Method Usage
completion = client.chat.completions.create( # [!code --]
response = client.responses.create( # [!code ++]
    model="nusantara-base",
    messages=[{"role": "user", "content": "Hello!"}] # [!code --]
    input="Hello!" # [!code ++]
)
```

### 2. Accessing the AI's Reply

This is a critical difference. The structure of the returned object in the SDK reflects the underlying API response.

* **Chat Completions**: The response is always nested inside a `choices` array. To get the text, you must access `response.choices[0].message.content`.
* **Responses**: The SDK provides a convenient helper property called `output_text` that directly gives you the concatenated text. However, the most reliable way is to access the `output` array and get the `.text` from the first element, as `output` can also contain other types of content like function calls.

<CodeGroup>
  ```python example completions icon="python" theme={null}
  # Chat Completions: Accessing the content
  # response = client.chat.completions.create(...)
  print(response.choices[0].message.content)
  ```

  ```python example response icon="python" theme={null}
  # Responses: Accessing the content
  # response = client.responses.create(...)

  # The reliable way (accessing the raw output structure)

  print(response.output[0].text)

  # The convenience helper (provided by the SDK)

  print(response.output_text)

  ```
</CodeGroup>

**Diff Comparison:**

```python icon="code" lines theme={null}
# Accessing AI Response Content
print(response.choices[0].message.content) # [!code --]
print(response.output[0].text) # [!code ++]
# Or use the convenience helper
print(response.output_text) # [!code ++]
```

### 3. Managing Conversation History

The Responses API was built to make multi-turn conversations easier, and this is reflected in the SDK usage.

* **Chat Completions**: You are fully responsible for managing the conversation. You must manually create a list, append the assistant's response, append the next user message, and send the entire list back every time.
* **Responses**: You can let the API manage the state. After the first turn, you simply pass the `previous_response_id` to continue the conversation. The SDK and your backend handle the rest.

<CodeGroup>
  ```python completion icon="python" theme={null}
  # Chat Completions: Manual state management
  messages = [{"role": "user", "content": "What is the capital of Indonesia?"}]
  completion = client.chat.completions.create(model="nusantara-base", messages=messages)

  # Manually append history for the next turn

  messages.append(completion.choices[0].message)
  messages.append({"role": "user", "content": "What is its population?"})
  next_completion = client.chat.completions.create(model="nusantara-base", messages=messages)
  ```

  ```python response icon="python" theme={null}
  # Responses: Automatic state management
  # First turn
  response1 = client.responses.create(
      model="nusantara-base",
      input="What is the capital of Indonesia?",
      store=True # Must be true to save the state
  )

  # Second turn - just use the ID
  response2 = client.responses.create(
      model="nusantara-base",
      previous_response_id=response1.id,
      input="What is its population?"
  )
  ```
</CodeGroup>

**Diff Comparison - Conversation Management:**

```python icon="code" lines theme={null}
# Manual history management (Chat Completions)
messages = [{"role": "user", "content": "What is the capital of Indonesia?"}] # [!code --]
completion = client.chat.completions.create(model="nusantara-base", messages=messages) # [!code --]

# Manually append history for next turn # [!code --]
messages.append(completion.choices[0].message) # [!code --]
messages.append({"role": "user", "content": "What is its population?"}) # [!code --]
next_completion = client.chat.completions.create(model="nusantara-base", messages=messages) # [!code --]

# Automatic state management (Responses) # [!code ++]
response1 = client.responses.create( # [!code ++]
    model="nusantara-base", # [!code ++]
    input="What is the capital of Indonesia?", # [!code ++]
    store=True # [!code ++]
) # [!code ++]

# Second turn - just use the ID # [!code ++]
response2 = client.responses.create( # [!code ++]
    model="nusantara-base", # [!code ++]
    previous_response_id=response1.id, # [!code ++]
    input="What is its population?" # [!code ++]
) # [!code ++]
```

## Complete Migration Example

Here's how you would migrate from Chat Completions to Responses:

```python icon="code" lines theme={null}
# Before: Chat Completions approach
import openai # [!code --]
client = openai.OpenAI(base_url="https://api.neosantara.ai/v1") # [!code --]

messages = [{"role": "user", "content": "Hello, how are you?"}] # [!code --]
completion = client.chat.completions.create( # [!code --]
    model="nusantara-base", # [!code --]
    messages=messages # [!code --]
) # [!code --]
ai_response = completion.choices[0].message.content # [!code --]

# After: Responses approach
import openai # [!code ++]
client = openai.OpenAI(base_url="https://api.neosantara.ai/v1") # [!code ++]

response = client.responses.create( # [!code ++]
    model="nusantara-base", # [!code ++]
    input="Hello, how are you?", # [!code ++]
    store=True # [!code ++]
) # [!code ++]
ai_response = response.output_text # [!code ++]
```

## Recommendation

| If you are...                 | You should use...                  | Why?                                                                                                             |
| :---------------------------- | :--------------------------------- | :--------------------------------------------------------------------------------------------------------------- |
| **Starting a new project**    | `client.responses.create()`        | It's simpler, more powerful, and offers state management, advanced reasoning, and strict structured outputs.     |
| **Migrating an existing app** | `client.chat.completions.create()` | It provides a seamless, drop-in replacement for code already written for the OpenAI `chat/completions` endpoint. |
