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

xAI SDK: client.chat.create

Lesson 4 of 12 Updated November 3, 2026 Developer
On this page
  1. The native xAI SDK
  2. Installation and authentication
  3. A conversation, not a request
  4. Generation parameters
  5. Streaming responses
  6. Error handling
  7. Asynchronous calls
  8. Key takeaways

Updated November 3, 2026. The previous version assumed the xai-sdk used the OpenAI SDK interface: messages as dictionaries, response.choices[0].message.content, the stream=True parameter, and a non-existent xai_sdk.errors module. With the actual SDK (version 1.21.0), that code fails on the first call: ValueError: unknown enum label "user". This lesson now follows the official SDK README, and every example has been executed against the xAI API (with a dummy key, to verify the call path and errors). Sources: xAI Python SDK · Best practices (xAI) · Debugging Errors (xAI).

The native xAI SDK

The official xAI SDK for Python, xai-sdk, does not use the REST Chat Completions endpoint: it is a gRPC library, with a synchronous client (Client) and an asynchronous client (AsyncClient), for Python 3.10 and up. It does not try to mimic the OpenAI SDK, and that is the first thing to keep in mind: its objects, methods, and errors have their own structure. To reuse code written for OpenAI, the next lesson shows the other path, the OpenAI SDK configured for the xAI API.

Installation and authentication

pip install xai-sdk

Authentication uses an API key created in the xAI console. Place it in the XAI_API_KEY environment variable, which the client reads automatically:

export XAI_API_KEY="your-api-key"

A conversation, not a request

With this SDK, client.chat.create() does not send anything: it creates a conversation object (chat), to which you add messages with append, then you request a response with sample(). Messages are built with the system, user, and assistant functions from the xai_sdk.chat module, not with dictionaries.

from xai_sdk import Client
from xai_sdk.chat import system, user

client = Client()  # reads XAI_API_KEY

chat = client.chat.create(
    model="grok-4.7",
    messages=[system("You are a helpful assistant. Respond in French.")],
)
chat.append(user("Explain deep learning in 3 sentences."))

response = chat.sample()
print(response.content)

The response exposes its text directly in response.content, alongside finish_reason, usage (tokens consumed), reasoning_content for models that expose it, and citations when a search was performed.

The API remains stateless: the chat object keeps the history for you. For a multi-turn conversation, add the response to the thread before the next question:

chat.append(response)
chat.append(user("Give a concrete example of an application."))
print(chat.sample().content)

Generation parameters

Parameters are passed to client.chat.create() and apply to the entire conversation:

chat = client.chat.create(
    model="grok-4.7",
    messages=[system("Respond only in JSON.")],
    temperature=0.7,
    top_p=0.95,
    reasoning_effort="medium",
)
  • model: the model identifier. xAI recommends grok-4.7 for all uses.
  • messages: the initial messages, built with system, user, and assistant.
  • temperature: the API accepts 0 to 2, but xAI caps it at 1 beyond that and recommends 0.7, with top_p at 0.95.
  • max_tokens: the maximum number of generated tokens. xAI best practices recommend setting it above the longest expected response, or leaving the default value.
  • reasoning_effort: the reasoning depth, from none to high (and xhigh on some models). The default depends on the model: xAI recommends setting it explicitly on every request, and noting it with every result.
  • response_format, tools, tool_choice: structured outputs and tool calling, covered later in the course.

stop also exists (up to four sequences), but xAI best practices specify that reasoning models do not accept it, nor presence_penalty and frequency_penalty.

Streaming responses

xAI recommends streaming, especially with reasoning models, whose responses can take a long time to arrive. It does not use a parameter: the conversation offers a second method, stream(), which returns a pair (response, chunk) at each step. chunk.content contains the text fragment that just arrived, and response accumulates the complete response throughout the stream.

chat = client.chat.create(model="grok-4.7")
chat.append(user("Write a short article on generative AI."))

for response, chunk in chat.stream():
    print(chunk.content, end="", flush=True)
print()

chat.append(response)  # the complete response joins the history

Error handling

Since the SDK speaks gRPC, its errors are grpc.RpcError (asynchronously, grpc.aio.AioRpcError, which inherit from them). You read their code with .code() and the message with .details():

import grpc
from xai_sdk import Client
from xai_sdk.chat import user

client = Client()
chat = client.chat.create(model="grok-4.7")
chat.append(user("Hello"))

try:
    response = chat.sample()
    print(response.content)
except grpc.RpcError as error:
    if error.code() == grpc.StatusCode.DEADLINE_EXCEEDED:
        print("Timeout exceeded: the request took too long.")
    else:
        print(f"Error {error.code().name}: {error.details()}")

Three behaviors are worth knowing. The SDK retries on its own requests that fail with UNAVAILABLE, up to five attempts with increasing delay; its README shows how to add other codes to this list, for example RESOURCE_EXHAUSTED, the gRPC code for exhausted quotas. The wait timeout defaults to 27 minutes for any request and is set at client creation (Client(timeout=…), in seconds). Do not reduce it too much: xAI advises planning for at least 900 seconds per request with its reasoning models. Finally, an invalid API key manifests as code INVALID_ARGUMENT and the message “Incorrect API key provided”: this is what the API returns today, verified November 3, 2026.

Asynchronous calls

For an asyncio application, replace Client with AsyncClient. Conversation creation remains synchronous; sample() and stream() are the ones that await:

import asyncio

from xai_sdk import AsyncClient
from xai_sdk.chat import user


async def main():
    client = AsyncClient()
    chat = client.chat.create(model="grok-4.7")
    chat.append(user("Hello"))

    response = await chat.sample()
    print(response.content)

    chat.append(response)
    chat.append(user("Summarize your response in one sentence."))
    async for response, chunk in chat.stream():
        print(chunk.content, end="", flush=True)


asyncio.run(main())

Key takeaways

  • xai-sdk is a gRPC SDK, with its own interface: it does not reuse the shape or objects of the OpenAI SDK
  • client.chat.create() creates a conversation; chat.append(user(...)) adds a message, chat.sample() returns the response, read in response.content
  • Messages are built with system, user, and assistant from xai_sdk.chat; dictionaries cause the call to fail
  • Streaming uses chat.stream(), which returns pairs (response, chunk)
  • Errors are grpc.RpcError; UNAVAILABLE is retried automatically, the default timeout is 27 minutes