Skip to main content
Lesson 8 of 12 · Chat Completions: OpenAI Compatibility

Response format: id, choices, and finish_reason

Lesson 8 of 12 Updated November 3, 2026 Developer
On this page
  1. Anatomy of a Chat Completions response
  2. Complete response structure
  3. The choices array
  4. finish_reason values
  5. Handling different cases
  6. Key takeaways

Updated November 3, 2026 based on the xAI Chat Completions API reference: only stop, length, and, in streaming, end_turn or null are documented for finish_reason; the tool_calls and content_filter values from the older version are not listed, and tool calls are detected via message.tool_calls. max_tokens is deprecated in favor of max_completion_tokens. Source: Chat Completions.

Anatomy of a Chat Completions response

Every call to the Chat Completions endpoint returns a JSON object structured with standardized fields. Understanding this structure is essential for extracting data correctly, handling edge cases, and debugging your integrations.

id
Unique identifier
choices
Response array
usage
Token counters
system_fingerprint
System fingerprint

Complete response structure

Here is an example of a typical response returned by the API:

{
  "id": "chatcmpl-abc123xyz",
  "object": "chat.completion",
  "created": 1712345678,
  "model": "grok-4.20-0309-reasoning",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Deep learning is a branch of machine learning..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 42,
    "completion_tokens": 156,
    "total_tokens": 198
  },
  "system_fingerprint": "fp_abc123"
}

Top-level fields

  • id: Unique identifier for the completion (format chatcmpl-...). Useful for tracking and debugging.
  • object: Always "chat.completion". Lets you distinguish this response type from other endpoints.
  • created: Unix timestamp of when the response was created.
  • model: The model that generated the response. May differ slightly from the requested model if you use an alias.
  • choices: Array containing the generated response or responses.
  • usage: Token counters for billing.
  • system_fingerprint: Fingerprint of the system configuration used.

The choices array

The choices field is an array that usually contains a single element (index 0). Each element contains:

  • index: Position in the array (starts at 0)
  • message: Object with role (always "assistant") and content (the generated text)
  • finish_reason: The reason generation stopped

To extract the text response:

# Python
response_text = response.choices[0].message.content
// JavaScript
const responseText = response.choices[0].message.content;

finish_reason values

The finish_reason field indicates why the model stopped generating text:

stop

"finish_reason": "stop"

The model finished its response naturally. This is the most common and desirable case: the model said everything it needed to say.

length

"finish_reason": "length"

Generation stopped because the output limit was reached—max_completion_tokens, which replaces the now deprecated max_tokens, and counts only the visible response. The response is therefore truncated: increase the limit or restart a continuation request.

end_turn or null in streaming

In streaming, each intermediate chunk carries "end_turn" or null in finish_reason; only the final chunk indicates the stop reason.

What the reference doesn’t document

The xAI API reference documents only these values. It mentions neither content_filter nor the value returned during a tool call: to know if the model requests a tool, check for the presence of message.tool_calls rather than the finish_reason value.

Handling different cases

In production, you must check finish_reason to adapt your behavior:

choice = response.choices[0]

if choice.message.tool_calls:
    # The model wants to call one or more tools
    for tool_call in choice.message.tool_calls:
        print(f"Tool requested: {tool_call.function.name}")

elif choice.finish_reason == "length":
    # Truncated response: notify the user or continue
    print(choice.message.content)
    print("[Truncated response: increase max_completion_tokens]")

else:
    # Complete response
    print(choice.message.content)

Key takeaways

  • The response contains a unique id, a choices array, and a usage object
  • Generated text is located in choices[0].message.content
  • finish_reason indicates why generation stopped: the reference documents stop and length (and end_turn or null in streaming)
  • Check finish_reason to spot truncated responses, and message.tool_calls for tool calls
  • The system_fingerprint identifies the system configuration used for generation