SpyBara
Go Premium

Documentation 2026-10-12 23:02 UTC to 2026-10-13 23:59 UTC

23 files changed +424 −103. View all changes and history on the product overview
2026
Sat 31 23:59 Fri 30 23:58 Thu 29 23:01 Wed 28 23:01 Tue 27 23:58 Mon 26 22:57 Sun 25 22:58 Sat 24 23:59 Fri 23 23:57 Thu 22 23:59 Wed 21 23:02 Tue 20 23:01 Mon 19 23:59 Sun 18 23:57 Sat 17 23:58 Fri 16 22:57 Thu 15 23:58 Wed 14 23:01 Tue 13 23:59 Mon 12 23:02 Sun 11 23:58 Sat 10 23:59 Fri 9 23:59 Thu 8 23:58 Wed 7 23:59 Tue 6 22:57 Mon 5 22:59 Sun 4 23:58 Sat 3 23:58 Fri 2 23:57 Thu 1 23:57
Details

6 6 

7## How It Works7## How It Works

8 8 

91. Your **server** requests an ephemeral token from SpaceXAI using your API key91. Your **server** requests an ephemeral token from SpaceXSI using your API key

102. Your server passes the ephemeral token to the **client**102. Your server passes the ephemeral token to the **client**

113. The **client** uses the ephemeral token to authenticate the WebSocket connection113. The **client** uses the ephemeral token to authenticate the WebSocket connection

124. The token expires automatically after the configured duration124. The token expires automatically after the configured duration


17 17 

18## Creating Ephemeral Tokens18## Creating Ephemeral Tokens

19 19 

20You need to set up a server endpoint to fetch the ephemeral token from SpaceXAI. The ephemeral token gives the holder scoped access to resources.20You need to set up a server endpoint to fetch the ephemeral token from SpaceXSI. The ephemeral token gives the holder scoped access to resources.

21 21 

22**Endpoint:** `POST https://api.x.ai/v1/realtime/client_secrets`22**Endpoint:** `POST https://api.x.ai/v1/realtime/client_secrets`

23 23 


47 47 

48@app.post("/session")48@app.post("/session")

49async def get_ephemeral_token():49async def get_ephemeral_token():

50 # Send request to xAI endpoint to retrieve the ephemeral token50 # Send request to SpaceXSI endpoint to retrieve the ephemeral token

51 async with httpx.AsyncClient() as client:51 async with httpx.AsyncClient() as client:

52 response = await client.post(52 response = await client.post(

53 url=SESSION_REQUEST_URL,53 url=SESSION_REQUEST_URL,


58 json={"expires_after": {"seconds": 300}},58 json={"expires_after": {"seconds": 300}},

59 )59 )

60 60 

61 # Return the response body from xAI with ephemeral token61 # Return the response body from SpaceXSI with ephemeral token

62 return response.json()62 return response.json()

63```63```

64 64 

Details

606 "audio": {606 "audio": {

607 "input": {607 "input": {

608 "transcription": {608 "transcription": {

609 "keyterms": ["xAI", "Grok", "Understand The Universe"]609 "keyterms": ["SpaceXSI", "Grok", "Understand The Universe"]

610 }610 }

611 }611 }

612 }612 }


621 audio: {621 audio: {

622 input: {622 input: {

623 transcription: {623 transcription: {

624 keyterms: ["xAI", "Grok", "Understand The Universe"]624 keyterms: ["SpaceXSI", "Grok", "Understand The Universe"]

625 }625 }

626 }626 }

627 }627 }


753 753 

754### Remote MCP Tools754### Remote MCP Tools

755 755 

756Use the `mcp` tool type to connect your voice agent to external [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) servers. This lets you extend your voice agent with third-party or custom tools without implementing them as client-side functions — SpaceXAI manages the MCP server connection and tool execution on your behalf.756Use the `mcp` tool type to connect your voice agent to external [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) servers. This lets you extend your voice agent with third-party or custom tools without implementing them as client-side functions — SpaceXSI manages the MCP server connection and tool execution on your behalf.

757 757 

758```pythonWithoutSDK758```pythonWithoutSDK

759session_config = {759session_config = {


896 896 

897> [!NOTE]897> [!NOTE]

898>898>

899> MCP tools are server-side tools — SpaceXAI handles the connection and execution automatically. Unlike custom function tools, you don't need to handle tool call responses in your client code. For more details on MCP tool configuration, see the [Remote MCP Tools](/developers/tools/remote-mcp) guide.899> MCP tools are server-side tools — SpaceXSI handles the connection and execution automatically. Unlike custom function tools, you don't need to handle tool call responses in your client code. For more details on MCP tool configuration, see the [Remote MCP Tools](/developers/tools/remote-mcp) guide.

900 900 

901### Custom Function Tools901### Custom Function Tools

902 902 


1048 1048 

1049> [!NOTE]1049> [!NOTE]

1050>1050>

1051> Server-side tools (web search, X search, collections, and MCP) are executed automatically by SpaceXAI — you don't need to handle their responses. Only custom function tools require client-side handling. For more details, see [Collections](/developers/rest-api-reference/collections), [Web Search](/developers/tools/web-search), [X Search](/developers/tools/x-search), and [Remote MCP Tools](/developers/tools/remote-mcp).1051> Server-side tools (web search, X search, collections, and MCP) are executed automatically by SpaceXSI — you don't need to handle their responses. Only custom function tools require client-side handling. For more details, see [Collections](/developers/rest-api-reference/collections), [Web Search](/developers/tools/web-search), [X Search](/developers/tools/x-search), and [Remote MCP Tools](/developers/tools/remote-mcp).

1052 1052 

1053### Handling Function Call Responses1053### Handling Function Call Responses

1054 1054 


1276 1276 

1277> [!NOTE]1277> [!NOTE]

1278>1278>

1279> `force_message` is an SpaceXAI extension. It is not part of the OpenAI Realtime API.1279> `force_message` is a SpaceXSI extension. It is not part of the OpenAI Realtime API.

1280 1280 

1281## Per-Response Instructions1281## Per-Response Instructions

1282 1282 


1501 1501 

1502#### Using the OpenAI SDK1502#### Using the OpenAI SDK

1503 1503 

1504If you are using the official OpenAI SDK, point the client at the SpaceXAI endpoint and supply your xAI API key:1504If you are using the official OpenAI SDK, point the client at the SpaceXSI endpoint and supply your xAI API key:

1505 1505 

1506```python customLanguage="pythonWithoutSDK"1506```python customLanguage="pythonWithoutSDK"

1507import asyncio1507import asyncio


1510# Before (OpenAI)1510# Before (OpenAI)

1511# client = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"])1511# client = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"])

1512 1512 

1513# After (xAI)1513# After (SpaceXSI)

1514client = AsyncOpenAI(1514client = AsyncOpenAI(

1515 api_key=os.environ["XAI_API_KEY"],1515 api_key=os.environ["XAI_API_KEY"],

1516 base_url="https://api.x.ai/v1",1516 base_url="https://api.x.ai/v1",


1537// Before (OpenAI)1537// Before (OpenAI)

1538// const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });1538// const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

1539 1539 

1540// After (xAI)1540// After (SpaceXSI)

1541const client = new OpenAI({1541const client = new OpenAI({

1542 apiKey: process.env.XAI_API_KEY,1542 apiKey: process.env.XAI_API_KEY,

1543 baseURL: "https://api.x.ai/v1",1543 baseURL: "https://api.x.ai/v1",

1544});1544});

1545 1545 

1546// Pass the configured client so the connection uses the xAI base URL and key1546// Pass the configured client so the connection uses the SpaceXSI base URL and key

1547const rt = new OpenAIRealtimeWS({ model: "grok-voice-latest" }, client);1547const rt = new OpenAIRealtimeWS({ model: "grok-voice-latest" }, client);

1548 1548 

1549rt.on("session.created", () => {1549rt.on("session.created", () => {


1576# url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview"1576# url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview"

1577# headers = {"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}"}1577# headers = {"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}"}

1578 1578 

1579# After (xAI)1579# After (SpaceXSI)

1580url = "wss://api.x.ai/v1/realtime?model=grok-voice-latest"1580url = "wss://api.x.ai/v1/realtime?model=grok-voice-latest"

1581headers = {"Authorization": f"Bearer {os.environ['XAI_API_KEY']}"}1581headers = {"Authorization": f"Bearer {os.environ['XAI_API_KEY']}"}

1582 1582 


1592// const url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview";1592// const url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview";

1593// const headers = { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` };1593// const headers = { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` };

1594 1594 

1595// After (xAI)1595// After (SpaceXSI)

1596const url = "wss://api.x.ai/v1/realtime?model=grok-voice-latest";1596const url = "wss://api.x.ai/v1/realtime?model=grok-voice-latest";

1597const headers = { Authorization: `Bearer ${process.env.XAI_API_KEY}` };1597const headers = { Authorization: `Bearer ${process.env.XAI_API_KEY}` };

1598 1598 


1634 1634 

1635## OpenAI Realtime API Compatibility1635## OpenAI Realtime API Compatibility

1636 1636 

1637The Grok Speech to Speech API is compatible with the [OpenAI Realtime API](https://developers.openai.com/api/docs/guides/realtime-conversations). Most OpenAI client libraries and SDKs work with the SpaceXAI endpoint by changing the base URL to `wss://api.x.ai/v1/realtime`. This section documents event naming differences and unsupported events.1637The Grok Speech to Speech API is compatible with the [OpenAI Realtime API](https://developers.openai.com/api/docs/guides/realtime-conversations). Most OpenAI client libraries and SDKs work with the SpaceXSI endpoint by changing the base URL to `wss://api.x.ai/v1/realtime`. This section documents event naming differences and unsupported events.

1638 1638 

1639### Event Naming Differences1639### Event Naming Differences

1640 1640 


1662| `output_audio_buffer.cleared` | WebRTC/SIP only. |1662| `output_audio_buffer.cleared` | WebRTC/SIP only. |

1663| `rate_limits.updated` | Not emitted. |1663| `rate_limits.updated` | Not emitted. |

1664 1664 

1665### SpaceXAI Extensions1665### SpaceXSI Extensions

1666 1666 

1667These events and features are SpaceXAI-specific and not part of the OpenAI Realtime API:1667These events and features are SpaceXSI-specific and not part of the OpenAI Realtime API:

1668 1668 

1669| Event / Feature | Description |1669| Event / Feature | Description |

1670|---|---|1670|---|---|

Details

6 6 

7### 1. Register the phone number7### 1. Register the phone number

8 8 

9Create a Direct SIP phone number and include the webhook details that should receive incoming-call events. Use `origin: "byo_trunk"` for a customer-owned number. Provisioning SpaceXAI phone numbers via API is not supported. SpaceXAI returns the webhook signing secret in the response.9Create a Direct SIP phone number and include the webhook details that should receive incoming-call events. Use `origin: "byo_trunk"` for a customer-owned number. Provisioning SpaceXSI phone numbers via API is not supported. SpaceXSI returns the webhook signing secret in the response.

10 10 

11Choose one SIP authentication method.11Choose one SIP authentication method.

12 12 

13The response includes a signing secret after you register the phone number. Store it securely; SpaceXAI returns it only once.13The response includes a signing secret after you register the phone number. Store it securely; SpaceXSI returns it only once.

14 14 

15Configure your carrier or PBX to route calls to:15Configure your carrier or PBX to route calls to:

16 16 

17 17 

18 18 

19If you provide `allowed_addresses`, make sure the list contains your provider's SIP signaling CIDR ranges. If you provide SIP digest credentials, configure your carrier with the same username and password; SpaceXAI never returns the password after creation.19If you provide `allowed_addresses`, make sure the list contains your provider's SIP signaling CIDR ranges. If you provide SIP digest credentials, configure your carrier with the same username and password; SpaceXSI never returns the password after creation.

20 20 

21### 2. Handle the incoming-call webhook21### 2. Handle the incoming-call webhook

22 22 

23When a caller dials the number, SpaceXAI sends a signed `realtime.call.incoming` webhook to the webhook URL. Verify the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers using the signing secret returned after you register the phone number, then read `data.call_id` from the payload.23When a caller dials the number, SpaceXSI sends a signed `realtime.call.incoming` webhook to the webhook URL. Verify the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers using the signing secret returned after you register the phone number, then read `data.call_id` from the payload.

24 24 

25The webhook has this shape:25The webhook has this shape:

26 26 


103 103 

104## Remove a phone number104## Remove a phone number

105 105 

106Delete the registration when SpaceXAI should stop answering the number. `phone_number_id` is in the create response. To find it later, list the team's numbers and match `phone_number`:106Delete the registration when SpaceXSI should stop answering the number. `phone_number_id` is in the create response. To find it later, list the team's numbers and match `phone_number`:

107 107 

108```bash customLanguage="bash"108```bash customLanguage="bash"

109curl "https://api.x.ai/v2/phone-numbers" \109curl "https://api.x.ai/v2/phone-numbers" \


115 -H "Authorization: Bearer $XAI_API_KEY"115 -H "Authorization: Bearer $XAI_API_KEY"

116```116```

117 117 

118A successful delete returns `204` with an empty body. SpaceXAI deletes that number's inbound SIP trunk and dispatch rule. The webhook record stays, and the phone number stays in your carrier account. A SpaceXAI-provisioned number is not deleted; the API returns `403`. See [Delete phone number](/developers/rest-api-reference/inference/voice#delete-phone-number).118A successful delete returns `204` with an empty body. SpaceXSI deletes that number's inbound SIP trunk and dispatch rule. The webhook record stays, and the phone number stays in your carrier account. A SpaceXSI-provisioned number is not deleted; the API returns `403`. See [Delete phone number](/developers/rest-api-reference/inference/voice#delete-phone-number).

119 119 

120## Call control120## Call control

121 121 


165 165 

166## Telephony providers166## Telephony providers

167 167 

168In every provider, the destination is the SpaceXAI SIP URI for your registered number:168In every provider, the destination is the SpaceXSI SIP URI for your registered number:

169 169 

170 170 

171 171 


227 227 

228### Does the session stay usable if a transfer fails?228### Does the session stay usable if a transfer fails?

229 229 

230Yes. While the REFER is pending, the WebSocket stays open and the caller hears dialtone. After a `502`, that same realtime session stays connected. The failed transfer is a no-op on the SpaceXAI side: the caller remains on the call, and the agent can keep talking.230Yes. While the REFER is pending, the WebSocket stays open and the caller hears dialtone. After a `502`, that same realtime session stays connected. The failed transfer is a no-op on the SpaceXSI side: the caller remains on the call, and the agent can keep talking.

231 231 

232This path does not automatically start a new session or inject a failure-reason prompt. If the agent should tell the caller why the transfer failed, read the `refer` HTTP response and continue on this session, or resume later as below.232This path does not automatically start a new session or inject a failure-reason prompt. If the agent should tell the caller why the transfer failed, read the `refer` HTTP response and continue on this session, or resume later as below.

233 233 

Details

483 483 

484## Related484## Related

485 485 

486* [Voice Overview](/developers/model-capabilities/audio/voice) — Overview of all SpaceXAI voice capabilities486* [Voice Overview](/developers/model-capabilities/audio/voice) — Overview of all SpaceXSI voice capabilities

487* [Text to Speech](/developers/model-capabilities/audio/text-to-speech) — Convert text to speech487* [Text to Speech](/developers/model-capabilities/audio/text-to-speech) — Convert text to speech

488* [API Reference — Speech to text](/developers/rest-api-reference/inference/voice#speech-to-text---rest) — Full REST endpoint specification488* [API Reference — Speech to text](/developers/rest-api-reference/inference/voice#speech-to-text---rest) — Full REST endpoint specification

489* [API Reference — Streaming](/developers/rest-api-reference/inference/voice#speech-to-text---streaming) — WebSocket streaming specification489* [API Reference — Streaming](/developers/rest-api-reference/inference/voice#speech-to-text---streaming) — WebSocket streaming specification

Details

1446 1446 

1447* [TTS Playground](https://console.x.ai/team/default/voice/text-to-speech?campaign=voice-docs-tts\&utm_source=docs\&utm_medium=referral\&utm_campaign=developers-model-capabilities-audio-text-to-speech\&utm_content=text-to-speech) - Try voices and speech tags in your browser1447* [TTS Playground](https://console.x.ai/team/default/voice/text-to-speech?campaign=voice-docs-tts\&utm_source=docs\&utm_medium=referral\&utm_campaign=developers-model-capabilities-audio-text-to-speech\&utm_content=text-to-speech) - Try voices and speech tags in your browser

1448* [Create an API Key](https://console.x.ai/team/default/api-keys?campaign=voice-docs-tts\&utm_source=docs\&utm_medium=referral\&utm_campaign=developers-model-capabilities-audio-text-to-speech\&utm_content=api-keys) - Get started with the API1448* [Create an API Key](https://console.x.ai/team/default/api-keys?campaign=voice-docs-tts\&utm_source=docs\&utm_medium=referral\&utm_campaign=developers-model-capabilities-audio-text-to-speech\&utm_content=api-keys) - Get started with the API

1449* [Voice Overview](/developers/model-capabilities/audio/voice) - Overview of all SpaceXAI voice capabilities1449* [Voice Overview](/developers/model-capabilities/audio/voice) - Overview of all SpaceXSI voice capabilities

1450* [Speech to Speech API](/developers/model-capabilities/audio/speech-to-speech) - Real-time voice conversations via WebSocket1450* [Speech to Speech API](/developers/model-capabilities/audio/speech-to-speech) - Real-time voice conversations via WebSocket

1451* [API Reference](/developers/rest-api-reference/inference/voice#text-to-speech---rest) - Full TTS endpoint specification1451* [API Reference](/developers/rest-api-reference/inference/voice#text-to-speech---rest) - Full TTS endpoint specification

1452* [List Voices](/developers/rest-api-reference/inference/voice#text-to-speech---list-voices) - Programmatically discover available voices1452* [List Voices](/developers/rest-api-reference/inference/voice#text-to-speech---list-voices) - Programmatically discover available voices

Details

80 -H "Authorization: Bearer $XAI_API_KEY" \80 -H "Authorization: Bearer $XAI_API_KEY" \

81 -H "Content-Type: application/json" \81 -H "Content-Type: application/json" \

82 -d '{82 -d '{

83 "text": "Welcome to xAI. How can I help you today?",83 "text": "Welcome to SpaceXSI. How can I help you today?",

84 "voice_id": "eve",84 "voice_id": "eve",

85 "language": "en"85 "language": "en"

86 }' \86 }' \


98 "Content-Type": "application/json",98 "Content-Type": "application/json",

99 },99 },

100 json={100 json={

101 "text": "Welcome to xAI. How can I help you today?",101 "text": "Welcome to SpaceXSI. How can I help you today?",

102 "voice_id": "eve",102 "voice_id": "eve",

103 "language": "en",103 "language": "en",

104 },104 },


118 "Content-Type": "application/json",118 "Content-Type": "application/json",

119 },119 },

120 body: JSON.stringify({120 body: JSON.stringify({

121 text: "Welcome to xAI. How can I help you today?",121 text: "Welcome to SpaceXSI. How can I help you today?",

122 voice_id: "eve",122 voice_id: "eve",

123 language: "en",123 language: "en",

124 }),124 }),

Details

29const result = await generateText({29const result = await generateText({

30 model: xai('grok-4.7'),30 model: xai('grok-4.7'),

31 system:31 system:

32 "You are Grok, a helpful and useful AI built by xAI.",32 "You are Grok, a helpful and useful AI built by SpaceXSI.",

33 prompt: 'Explain how neural networks learn in two sentences.',33 prompt: 'Explain how neural networks learn in two sentences.',

34});34});

35 35 


72 messages: [72 messages: [

73 {73 {

74 role: "system",74 role: "system",

75 content: "You are Grok, a helpful and useful AI built by xAI."75 content: "You are Grok, a helpful and useful AI built by SpaceXSI."

76 },76 },

77 {77 {

78 role: "user",78 role: "user",


93 "messages": [93 "messages": [

94 {94 {

95 "role": "system",95 "role": "system",

96 "content": "You are Grok, a helpful and useful AI built by xAI."96 "content": "You are Grok, a helpful and useful AI built by SpaceXSI."

97 },97 },

98 {98 {

99 "role": "user",99 "role": "user",

Details

1#### Model Capabilities

2 

3# Best Practices Guide

4 

5This guide collects the practices that get the best results from Grok text and reasoning models on the xAI API. It covers which API to use, how to carry reasoning across turns, how to lower cost with prompt caching, how to configure requests, and how to run evaluations.

6 

7Start with these settings:

8 

9| Setting | Recommendation |

10|---|---|

11| [API](#use-the-responses-api) | Use the [Responses API](/developers/model-capabilities/text/generate-text). Chat Completions is deprecated. |

12| [Multi-turn history](#send-encrypted-reasoning-back-with-every-turn) | Send the encrypted reasoning content back to the API with every turn. |

13| [Prompt caching](#use-prompt-caching-to-lower-cost) | Give each conversation its own `prompt_cache_key`, and only append to the conversation. |

14| [Reasoning effort](#reasoning-effort) | Set it explicitly on every request, and record it with every result. |

15| [Streaming and timeouts](#streaming-and-timeouts) | Prefer streaming. Allow at least 900 seconds per request, and 1800 seconds or more for long-running evals. |

16| [Output length](#output-length) | Set `max_output_tokens` above your longest expected answer, or leave it at its 128,000-token default. |

17| [Sampling](#sampling-parameters) | Set `temperature` to 0.7 and `top_p` to 0.95, and don't stray far from them. |

18 

19## Use the Responses API

20 

21Use the Responses API (`POST /v1/responses`) with Grok reasoning models. The Chat Completions API is deprecated, and it has no field for the model's encrypted reasoning, so every multi-turn or tool-calling conversation sent through it discards the model's earlier thinking. New capabilities also arrive on the Responses API first.

22 

23If your code already uses Chat Completions, the [comparison guide](/developers/model-capabilities/text/comparison) maps each parameter and response field to its Responses API equivalent.

24 

25> [!WARNING]

26>

27> Chat Completions is offered only as a legacy endpoint. Results from it understate what Grok reasoning models can do, especially across multiple turns and tool calls.

28 

29## Send encrypted reasoning back with every turn

30 

31Grok reasoning models think before they answer. The Responses API returns that reasoning as an encrypted `reasoning` item in the response's `output` array, alongside the message and any function calls. When you send these items back unchanged in the next request's `input`, the model stays aware of its earlier reasoning traces. This drastically improves performance on multi-turn conversations and agent loops, where each step builds on decisions the model already reasoned through.

32 

33There are two ways to keep reasoning in the conversation:

34 

35* Chain requests with `previous_response_id` while `store` is on (the default). SpaceXAI stores the reasoning with the response and restores it for you.

36* Manage the history yourself with `store: false`. Request the reasoning with `include: ["reasoning.encrypted_content"]` and append every output item to the next request's `input`. Each request is then self-contained and carries the full conversation, which you can log and replay.

37 

38`grok-4.7` returns `reasoning.encrypted_content` on every Responses API response, whether or not `include` lists it. Your code still has to send it back. See [Adding encrypted thinking content](/developers/model-capabilities/text/generate-text#adding-encrypted-thinking-content) for the full reference.

39 

40The following loop runs a scripted multi-turn conversation. It streams each turn, carries the encrypted reasoning forward, reuses one `prompt_cache_key` for the whole conversation, and prints how many input tokens were served from the cache:

41 

42```python customLanguage="pythonOpenAISDK"

43import os

44import uuid

45 

46import httpx

47from openai import OpenAI

48 

49client = OpenAI(

50 api_key=os.getenv("XAI_API_KEY"),

51 base_url="https://api.x.ai/v1",

52 timeout=httpx.Timeout(900.0),

53)

54 

55conversation_id = str(uuid.uuid4())

56history = [{"role": "system", "content": "You are a careful analyst. Answer concisely."}]

57 

58turns = [

59 "A train leaves at 9:40 and arrives at 13:05. How long is the trip?",

60 "The return trip is 20% faster. When does it arrive if it leaves at 15:00?",

61]

62 

63for turn in turns:

64 history.append({"role": "user", "content": turn})

65 stream = client.responses.create(

66 model="grok-4.7",

67 input=history,

68 reasoning={"effort": "high"},

69 temperature=0.7,

70 top_p=0.95,

71 include=["reasoning.encrypted_content"],

72 store=False,

73 stream=True,

74 extra_body={"prompt_cache_key": conversation_id},

75 )

76 response = None

77 for event in stream:

78 if event.type == "response.output_text.delta":

79 print(event.delta, end="", flush=True)

80 elif event.type in ("response.completed", "response.incomplete"):

81 response = event.response

82 print()

83 # Append every output item, including reasoning items with encrypted_content.

84 history.extend(response.output)

85 print(f"Cached tokens: {response.usage.input_tokens_details.cached_tokens}")

86```

87 

88```javascript customLanguage="javascriptOpenAISDK"

89import { randomUUID } from "node:crypto";

90import OpenAI from "openai";

91 

92const client = new OpenAI({

93 apiKey: process.env.XAI_API_KEY,

94 baseURL: "https://api.x.ai/v1",

95 timeout: 900000,

96});

97 

98const conversationId = randomUUID();

99const history = [

100 { role: "system", content: "You are a careful analyst. Answer concisely." },

101];

102 

103const turns = [

104 "A train leaves at 9:40 and arrives at 13:05. How long is the trip?",

105 "The return trip is 20% faster. When does it arrive if it leaves at 15:00?",

106];

107 

108for (const turn of turns) {

109 history.push({ role: "user", content: turn });

110 const stream = await client.responses.create({

111 model: "grok-4.7",

112 input: history,

113 reasoning: { effort: "high" },

114 temperature: 0.7,

115 top_p: 0.95,

116 include: ["reasoning.encrypted_content"],

117 store: false,

118 stream: true,

119 prompt_cache_key: conversationId,

120 });

121 let response;

122 for await (const event of stream) {

123 if (event.type === "response.output_text.delta") {

124 process.stdout.write(event.delta);

125 } else if (event.type === "response.completed" || event.type === "response.incomplete") {

126 response = event.response;

127 }

128 }

129 console.log();

130 // Append every output item, including reasoning items with encrypted_content.

131 history.push(...response.output);

132 console.log(`Cached tokens: ${response.usage.input_tokens_details.cached_tokens}`);

133}

134```

135 

136```python customLanguage="pythonXAI"

137import os

138import uuid

139 

140from xai_sdk import Client

141from xai_sdk.chat import system, user

142 

143conversation_id = str(uuid.uuid4())

144 

145client = Client(

146 api_key=os.getenv("XAI_API_KEY"),

147 timeout=900,

148 # Routes every turn of this conversation to the same server for cache reuse.

149 metadata=(("x-grok-conv-id", conversation_id),),

150)

151 

152chat = client.chat.create(

153 model="grok-4.7",

154 reasoning_effort="high",

155 temperature=0.7,

156 top_p=0.95,

157 store_messages=False,

158 use_encrypted_content=True,

159)

160chat.append(system("You are a careful analyst. Answer concisely."))

161 

162turns = [

163 "A train leaves at 9:40 and arrives at 13:05. How long is the trip?",

164 "The return trip is 20% faster. When does it arrive if it leaves at 15:00?",

165]

166 

167for turn in turns:

168 chat.append(user(turn))

169 for response, chunk in chat.stream():

170 print(chunk.content, end="", flush=True)

171 print()

172 # Appending the response also appends its encrypted reasoning.

173 chat.append(response)

174 print(f"Cached tokens: {response.usage.cached_prompt_text_tokens}")

175```

176 

177The Vercel AI SDK carries encrypted reasoning automatically when you chain requests with `previousResponseId`; see [Reasoning](/developers/model-capabilities/text/reasoning#encrypted-reasoning-content).

178 

179### Keep reasoning in agent loops

180 

181Tool-calling workloads need the same treatment. When the model calls a function, its reasoning item arrives in the same `output` array as the `function_call`. Append the whole array, then your `function_call_output` items, so the model resumes with its plan intact when it reads the tool result:

182 

183```python customLanguage="pythonOpenAISDK"

184import json

185 

186# client, tools, task_prompt, run_tool, and conversation_id come from your code.

187def stream_turn(input_items):

188 stream = client.responses.create(

189 model="grok-4.7",

190 input=input_items,

191 tools=tools,

192 reasoning={"effort": "high"},

193 temperature=0.7,

194 top_p=0.95,

195 include=["reasoning.encrypted_content"],

196 store=False,

197 stream=True,

198 extra_body={"prompt_cache_key": conversation_id},

199 )

200 for event in stream:

201 if event.type in ("response.completed", "response.incomplete"):

202 return event.response

203 

204input_items = [{"role": "user", "content": task_prompt}]

205 

206while True:

207 response = stream_turn(input_items)

208 # Reasoning, messages, and function calls all go back in order.

209 input_items.extend(response.output)

210 

211 calls = [item for item in response.output if item.type == "function_call"]

212 if not calls:

213 break

214 

215 for call in calls:

216 result = run_tool(call.name, json.loads(call.arguments))

217 input_items.append({

218 "type": "function_call_output",

219 "call_id": call.call_id,

220 "output": json.dumps(result),

221 })

222 

223print(response.output_text)

224```

225 

226Code drops reasoning most often in one of these ways:

227 

228* It extracts `output_text` and appends it as a plain assistant message, discarding the reasoning and function call items around it.

229* It edits, reorders, or filters output items before sending them back. Pass them back exactly as received.

230* It rebuilds the conversation from a transcript in a different format, such as a Chat Completions `messages` array, between turns.

231 

232For long agent loops, [WebSocket mode](/developers/advanced-api-usage/websocket-mode) reduces per-turn latency, and [context compaction](/developers/advanced-api-usage/context-compaction) keeps long conversations within the context window.

233 

234## Use prompt caching to lower cost

235 

236The xAI API caches prompts automatically, and cached input tokens are billed at a lower rate than regular input tokens; see [Pricing](/developers/pricing) for each model's cached token price. The cache matches your input from the start: when a request begins with exactly the same items as an earlier request, that matching prefix is served from the cache, and only the new items are processed. Multi-turn conversations and agent loops benefit the most, because each turn resends everything before it.

237 

238To get the most cache hits:

239 

240* Give each conversation its own [`prompt_cache_key`](/developers/advanced-api-usage/prompt-caching/maximizing-cache-hits) and reuse it on every turn. Cache entries live on individual servers, and the key routes every turn of the conversation to the same one. A UUID or your application's session ID works well. With the xAI SDK, send the same value as `x-grok-conv-id` gRPC metadata.

241* Only append to the conversation. Editing, removing, or reordering earlier items breaks the prefix, and everything after the change is processed at the full price.

242* Send the encrypted reasoning back unchanged. For reasoning models, leaving it out is the most common cause of cache misses. Chaining with `previous_response_id` keeps the prefix intact as well.

243* Put static content first. System prompts, few-shot examples, and reference documents at the start of the input form a stable prefix that every turn can reuse.

244 

245Check `usage.input_tokens_details.cached_tokens` on each response. It should grow with each turn of a conversation; if it stays at 0, check that every turn sends the same `prompt_cache_key` and that earlier items are unchanged. Caching works with streaming and with tool calls, but cache hits are not guaranteed, because entries can be evicted under load. See [What Breaks Caching](/developers/advanced-api-usage/prompt-caching/multi-turn) for examples.

246 

247## Configure requests for reasoning models

248 

249Reasoning models spend tokens and time thinking before they respond, so reasoning effort, streaming and timeouts, output limits, and sampling parameters all affect your results.

250 

251### Reasoning effort

252 

253On the Responses API, `reasoning.effort` controls how much the model thinks. The supported values and the default depend on the model; `grok-4.7` defaults to `"high"`, while `grok-4.3` defaults to `"low"` and also accepts `"none"`. Set the effort explicitly on every request so a default never decides your result, and choose the effort you intend to run in production. If cost or latency matters, compare effort levels and weigh quality against tokens and time. See the [`reasoning_effort`](/developers/model-capabilities/text/reasoning#the-reasoning_effort-parameter) parameter for the supported values per model.

254 

255### Streaming and timeouts

256 

257Prefer [streaming](/developers/model-capabilities/text/streaming) (`stream: true`) to non-streaming requests. A streamed response sends events as the model works, which keeps the connection from dropping during long generations, and the final `response.completed` event carries the full response, including the encrypted reasoning items to send back.

258 

259Set the client timeout to at least 900 seconds, as the examples in this guide do. High reasoning effort on complex problems can run for several minutes, and long-running evals such as Humanity's Last Exam (HLE) can take upwards of 1800 seconds per request. Raise the timeout above your longest expected request so slow requests are not recorded as failures.

260 

261### Output length

262 

263`max_output_tokens` caps only the visible answer; reasoning and function call tokens do not count toward it. When unset, it defaults to 128,000 tokens. A tight cap cuts the answer off, so set the cap above the longest answer you expect, and treat responses with `status: "incomplete"` as truncated.

264 

265### Sampling parameters

266 

267> [!WARNING]

268>

269> Set `temperature` to 0.7 and `top_p` to 0.95, and don't deviate far from these values. Grok models don't respond well to other sampling settings, and quality usually drops when you change them.

270 

271Set both values explicitly on every request so your results don't depend on server defaults, and use the same values for every model you compare.

272 

273### Errors, retries, and rate limits

274 

275Separate infrastructure failures from model failures. Retry `429` and `5xx` responses with exponential backoff, and rerun any request that still fails until it gets a response. Large workloads should respect your team's [rate limits](/developers/rate-limits).

276 

277## Evaluate Grok models

278 

279A good evaluation tells you how a model will behave on your workload, which is rarely the same as how it scores on a public leaderboard. Apply the settings above, then design and run the eval with these practices.

280 

281### Design the eval

282 

283Start by writing down what success means for your application in terms you can measure. "Answers support questions well" is too vague to test. A testable version is "resolves at least 85% of a 500-ticket sample without inventing a policy, with a median latency under 20 seconds." Most applications need several criteria at once, such as task accuracy, instruction following, format compliance, safety, latency, and cost.

284 

285Build the dataset from the work the model will actually do. Production logs, with personal data removed, are the most representative source; add hand-written edge cases, adversarial inputs, and long or multi-turn examples. Check whether public benchmark items might appear in training data, and keep in mind each model's knowledge cutoff (May 2026 for `grok-4.7`) when questions depend on recent events. If the task needs current information, enable [web search](/developers/tools/web-search) and evaluate that configuration directly.

286 

287Choose the cheapest grader that is reliable for the criterion:

288 

289| Grader | Best for | Watch out for |

290|---|---|---|

291| Code | Exact answers, unit tests, schema validation, tool-call arguments | Rejecting correct answers in an unexpected format |

292| Model as judge | Open-ended quality, rubric scoring, pairwise comparison | Position bias, preference for longer answers, drift from human judgment |

293| Human review | Calibrating other graders, high-stakes or subjective tasks | Cost, speed, and disagreement between reviewers |

294 

295When you use a model as a judge, give it a specific rubric with examples of each score, ask it to reason before it scores, and randomize the order of answers in pairwise comparisons. Measure its agreement with human labels on a sample before you trust it at scale.

296 

297Prompt each model fairly. Grok reasoning models reason before they answer, so state the task, constraints, and output format directly. If you tuned a prompt for another model, spend comparable effort tuning it for Grok before you compare scores.

298 

299### Run, measure, and compare

300 

301Reasoning models are not deterministic, so a single run can mislead you. Run each item several times, report the mean and spread, and use pass@k where any one correct attempt counts. Treat small differences between models with suspicion until they hold across runs.

302 

303If you must exclude an item that keeps failing, exclude it for every model you compare so all of them are scored on the same set, and report how many items you excluded; dropping failures for one model alone inflates its score.

304 

305Log the full response for every request, including its `usage` object. `usage.output_tokens_details.reasoning_tokens` reports how many tokens the model spent reasoning, `usage.input_tokens_details.cached_tokens` shows how much of the input came from the cache, and `usage.cost_in_usd_ticks` gives the exact billed cost of each request; together with wall-clock latency, they let you compare quality per dollar and per second. See [Cost Tracking](/developers/cost-tracking) for converting ticks to dollars. Record the model name, reasoning effort, sampling parameters, date, and harness version with every result, because models and harnesses change.

306 

307Before you report results, confirm that:

308 

309* Every request used the Responses API.

310* Multi-turn and tool-calling items carried their encrypted reasoning forward unchanged.

311* Reasoning effort, sampling parameters, model name, and harness version are recorded and match across the models you compare.

312* Failed requests were retried, any exclusions apply to every model equally, and truncated responses were flagged.

313 

314## Related

315 

316* [Generate Text](/developers/model-capabilities/text/generate-text): the Responses API, stored conversations, and encrypted thinking content

317* [Reasoning](/developers/model-capabilities/text/reasoning): reasoning effort, encrypted reasoning, and reasoning summaries

318* [Streaming](/developers/model-capabilities/text/streaming): streaming responses with Server-Sent Events

319* [Prompt Caching](/developers/advanced-api-usage/prompt-caching): how caching works and how to maximize cache hits

320* [Function Calling](/developers/tools/function-calling): defining tools and handling tool calls

321* [Comparison with Chat Completions](/developers/model-capabilities/text/comparison): migrating from Chat Completions

Details

3# Generate Text3# Generate Text

4 4 

5The Responses API is the preferred way of interacting with our models via API. It allows optional **stateful interactions** with our models,5The Responses API is the preferred way of interacting with our models via API. It allows optional **stateful interactions** with our models,

6where **previous input prompts, reasoning content, and model responses are saved and stored on SpaceXAI's servers**. You can continue the interaction by appending new6where **previous input prompts, reasoning content, and model responses are saved and stored on SpaceXSI's servers**. You can continue the interaction by appending new

7prompt messages instead of resending the full conversation. This behavior is on by default. If you would like to store your request/response locally, please see [Disable storing previous request/response on server](#disable-storing-previous-requestresponse-on-server).7prompt messages instead of resending the full conversation. This behavior is on by default. If you would like to store your request/response locally, please see [Disable storing previous request/response on server](#disable-storing-previous-requestresponse-on-server).

8 8 

9**The responses will be stored for 30 days, after which they will be removed. This means you can use the response ID to retrieve or continue a conversation within 30 days of sending the request.**9**The responses will be stored for 30 days, after which they will be removed. This means you can use the response ID to retrieve or continue a conversation within 30 days of sending the request.**

Details

149 149 

150### Built-in Tools Support150### Built-in Tools Support

151 151 

152SpaceXAI provides a set of built-in tools you can enable in the request to help with the most common use cases, e.g., `web_search`, `x_search`, `code_execution`, `collections_search`. Check out [this doc](/developers/tools/overview) for more information.152SpaceXSI provides a set of built-in tools you can enable in the request to help with the most common use cases, e.g., `web_search`, `x_search`, `code_execution`, `collections_search`. Check out [this doc](/developers/tools/overview) for more information.

153 153 

154Once you enable those tools in the request, the server will perform the agent loop to invoke those tools on the server side based on your query until the final answer is generated.154Once you enable those tools in the request, the server will perform the agent loop to invoke those tools on the server side based on your query until the final answer is generated.

155 155 

Details

15> [!NOTE]15> [!NOTE]

16> Always returned for grok-4.716> Always returned for grok-4.7

17>17>

18> On the Responses API, `grok-4.7` returns `reasoning.encrypted_content` on every response, whether or not `include` lists it, together with the encrypted outputs of any server-side tools. Reasoning items in the output carry an `encrypted_content` field; pass them back unchanged in the next request's `input` so the model keeps its reasoning across turns even when you manage conversation history yourself. Unlike an explicit `include`, this default does not stop SpaceXAI from storing the thinking trace server-side for rehydration, so clients that ignore the field keep working as before; whether the response itself is stored for `previous_response_id` is governed by `store`, not by this setting. Chat Completions is unaffected; it has no field for the ciphertext.18> On the Responses API, `grok-4.7` returns `reasoning.encrypted_content` on every response, whether or not `include` lists it, together with the encrypted outputs of any server-side tools. Reasoning items in the output carry an `encrypted_content` field; pass them back unchanged in the next request's `input` so the model keeps its reasoning across turns even when you manage conversation history yourself. Unlike an explicit `include`, this default does not stop SpaceXSI from storing the thinking trace server-side for rehydration, so clients that ignore the field keep working as before; whether the response itself is stored for `previous_response_id` is governed by `store`, not by this setting. Chat Completions is unaffected; it has no field for the ciphertext.

19 19 

20> [!TIP]20> [!TIP]

21>21>

Details

22const result = streamText({22const result = streamText({

23 model: xai.responses('grok-4.7'),23 model: xai.responses('grok-4.7'),

24 system:24 system:

25 "You are Grok, a helpful and useful AI built by xAI.",25 "You are Grok, a helpful and useful AI built by SpaceXSI.",

26 prompt: 'Explain how neural networks learn in two sentences.',26 prompt: 'Explain how neural networks learn in two sentences.',

27});27});

28 28 


45stream = client.chat.completions.create(45stream = client.chat.completions.create(

46 model="grok-4.7",46 model="grok-4.7",

47 messages=[47 messages=[

48 {"role": "system", "content": "You are Grok, a helpful and useful AI built by xAI."},48 {"role": "system", "content": "You are Grok, a helpful and useful AI built by SpaceXSI."},

49 {"role": "user", "content": "Explain how neural networks learn in two sentences."},49 {"role": "user", "content": "Explain how neural networks learn in two sentences."},

50 ],50 ],

51 stream=True51 stream=True


67const stream = await openai.chat.completions.create({67const stream = await openai.chat.completions.create({

68 model: "grok-4.7",68 model: "grok-4.7",

69 messages: [69 messages: [

70 { role: "system", content: "You are Grok, a helpful and useful AI built by xAI." },70 { role: "system", content: "You are Grok, a helpful and useful AI built by SpaceXSI." },

71 {71 {

72 role: "user",72 role: "user",

73 content: "Explain how neural networks learn in two sentences.",73 content: "Explain how neural networks learn in two sentences.",


93 "messages": [93 "messages": [

94 {94 {

95 "role": "system",95 "role": "system",

96 "content": "You are Grok, a helpful and useful AI built by xAI."96 "content": "You are Grok, a helpful and useful AI built by SpaceXSI."

97 },97 },

98 {98 {

99 "role": "user",99 "role": "user",


118 118 

119chat = client.chat.create(model="grok-4.7")119chat = client.chat.create(model="grok-4.7")

120chat.append(120chat.append(

121 system("You are Grok, a helpful and useful AI built by xAI."),121 system("You are Grok, a helpful and useful AI built by SpaceXSI."),

122)122)

123chat.append(123chat.append(

124 user("Explain how neural networks learn in two sentences.")124 user("Explain how neural networks learn in two sentences.")

Details

15 15 

16The primary and most flexible method is to use the `response_format` parameter. By setting `response_format.type` to `"json_schema"` and providing your schema under `response_format.json_schema`, you can define exactly what structured output the model should return. The parameter also accepts `"json_object"` for any well-formed JSON when you don't need a specific structure, or `"text"` (the default) for free-form text.16The primary and most flexible method is to use the `response_format` parameter. By setting `response_format.type` to `"json_schema"` and providing your schema under `response_format.json_schema`, you can define exactly what structured output the model should return. The parameter also accepts `"json_object"` for any well-formed JSON when you don't need a specific structure, or `"text"` (the default) for free-form text.

17 17 

18The second way is through tool calling. When you define tools, SpaceXAI models will always generate tool call arguments that strictly conform to the tool’s input JSON Schema (the `strict` flag is implicitly always `true`).18The second way is through tool calling. When you define tools, SpaceXSI models will always generate tool call arguments that strictly conform to the tool’s input JSON Schema (the `strict` flag is implicitly always `true`).

19 19 

20> [!NOTE]20> [!NOTE]

21>21>

Details

196}196}

197```197```

198 198 

199Videos are returned as temporary URLs. Access the SpaceXAI-hosted URL directly when you need it, or download/process it promptly if you need to keep a copy.199Videos are returned as temporary URLs. Access the SpaceXSI-hosted URL directly when you need it, or download/process it promptly if you need to keep a copy.

200 200 

201## Configuration201## Configuration

202 202 


651| `permission_denied` | The API key or team does not have permission for the requested video operation. | Confirm the API key belongs to the right team and that the team has access to the requested capability. |651| `permission_denied` | The API key or team does not have permission for the requested video operation. | Confirm the API key belongs to the right team and that the team has access to the requested capability. |

652| `failed_precondition` | The requested operation is not available for the selected model or settings, such as video editing, video extension, or a requested resolution that the model cannot process. | Change the model, mode, resolution, or other request settings. |652| `failed_precondition` | The requested operation is not available for the selected model or settings, such as video editing, video extension, or a requested resolution that the model cannot process. | Change the model, mode, resolution, or other request settings. |

653| `service_unavailable` | Video generation is temporarily overloaded. | Retry the request later. |653| `service_unavailable` | Video generation is temporarily overloaded. | Retry the request later. |

654| `internal_error` | The service could not complete the generation because of an internal failure. | Retry the request. If the error persists, contact SpaceXAI support with the `request_id`. |654| `internal_error` | The service could not complete the generation because of an internal failure. | Retry the request. If the error persists, contact SpaceXSI support with the `request_id`. |

655 655 

656Authentication errors, missing models, and rate limits are returned synchronously as standard API errors before a video job is created, so they do not appear in the `error.code` field of a failed video result.656Authentication errors, missing models, and rate limits are returned synchronously as standard API errors before a video job is created, so they do not appear in the `error.code` field of a failed video result.

657 657 


679 679 

680## Response Details680## Response Details

681 681 

682The SDK response includes the generated video and provider-specific metadata. In the AI SDK, the SpaceXAI-hosted output URL is available at `providerMetadata.xai.videoUrl`.682The SDK response includes the generated video and provider-specific metadata. In the AI SDK, the SpaceXSI-hosted output URL is available at `providerMetadata.xai.videoUrl`.

683 683 

684```javascript customLanguage="javascriptAISDK"684```javascript customLanguage="javascriptAISDK"

685const result = await generateVideo({685const result = await generateVideo({

rate-limits.md +1 −1

Details

45| grok-imagine-image | T0: 6, T1: 12, T2: 25, T3: 50, T4: 100 | — |45| grok-imagine-image | T0: 6, T1: 12, T2: 25, T3: 50, T4: 100 | — |

46| grok-imagine-image-quality | T0: 6, T1: 12, T2: 25, T3: 50, T4: 100 | — |46| grok-imagine-image-quality | T0: 6, T1: 12, T2: 25, T3: 50, T4: 100 | — |

47| grok-imagine-video-1.5 | T0: 10, T1: 20, T2: 39, T3: 79, T4: 158 | — |47| grok-imagine-video-1.5 | T0: 10, T1: 20, T2: 39, T3: 79, T4: 158 | — |

48| grok-imagine-video | T0: 10, T1: 20, T2: 39, T3: 79, T4: 158 | — |

49| grok-imagine-video-1.5-lite | T0: 10, T1: 20, T2: 39, T3: 79, T4: 158 | — |48| grok-imagine-video-1.5-lite | T0: 10, T1: 20, T2: 39, T3: 79, T4: 158 | — |

49| grok-imagine-video | T0: 10, T1: 20, T2: 39, T3: 79, T4: 158 | — |

50 50 

51**Voice & Audio**51**Voice & Audio**

52 52 

Details

19 19 

20### How It Works20### How It Works

21 21 

22The key difference when mixing server-side and client-side tools is that **server-side tools are executed automatically by SpaceXAI**, while **client-side tools require developer intervention**:22The key difference when mixing server-side and client-side tools is that **server-side tools are executed automatically by SpaceXSI**, while **client-side tools require developer intervention**:

23 23 

241. Define your client-side tools using [standard function calling patterns](/developers/tools/function-calling)241. Define your client-side tools using [standard function calling patterns](/developers/tools/function-calling)

252. Include both server-side and client-side tools in your request252. Include both server-side and client-side tools in your request

263. **SpaceXAI automatically executes any server-side tools** the model decides to use (web search, code execution, etc.)263. **SpaceXSI automatically executes any server-side tools** the model decides to use (web search, code execution, etc.)

274. **When the model calls client-side tools, execution pauses** - SpaceXAI returns the tool calls to you instead of executing them274. **When the model calls client-side tools, execution pauses** - SpaceXSI returns the tool calls to you instead of executing them

285. **Detect and execute client-side tool calls yourself**, then append the results back to continue the conversation285. **Detect and execute client-side tool calls yourself**, then append the results back to continue the conversation

296. **Repeat this process** until the model generates a final response with no additional client-side tool calls296. **Repeat this process** until the model generates a final response with no additional client-side tool calls

30 30 


364 364 

365### Store the Conversation History Remotely365### Store the Conversation History Remotely

366 366 

367You can choose to store the conversation history remotely on the SpaceXAI server, and every time you want to continue the conversation, you can pick up from the last response where you want to resume from.367You can choose to store the conversation history remotely on the SpaceXSI server, and every time you want to continue the conversation, you can pick up from the last response where you want to resume from.

368 368 

369There are only 2 extra steps:369There are only 2 extra steps:

370 370 

3711. Add the parameter `store_messages=True` when making the first agentic request. This tells the service to store the entire conversation history on SpaceXAI servers, including the model's reasoning, server-side tool calls, and corresponding responses.3711. Add the parameter `store_messages=True` when making the first agentic request. This tells the service to store the entire conversation history on SpaceXSI servers, including the model's reasoning, server-side tool calls, and corresponding responses.

3722. Pass `previous_response_id=response.id` when creating the follow-up conversation, where `response` is the response returned by `chat.sample()` or `chat.stream()` from the conversation that you wish to continue.3722. Pass `previous_response_id=response.id` when creating the follow-up conversation, where `response` is the response returned by `chat.sample()` or `chat.stream()` from the conversation that you wish to continue.

373 373 

374Note that the follow-up conversation does not need to use the same tools, model parameters, or any other configuration as the initial conversation—it will still be fully hydrated with the complete agentic state from the previous interaction.374Note that the follow-up conversation does not need to use the same tools, model parameters, or any other configuration as the initial conversation—it will still be fully hydrated with the complete agentic state from the previous interaction.


386 tools=[web_search(), x_search()],386 tools=[web_search(), x_search()],

387 store_messages=True,387 store_messages=True,

388)388)

389chat.append(user("What is xAI?"))389chat.append(user("What is SpaceXSI?"))

390print("\\n\\n##### First turn #####\\n")390print("\\n\\n##### First turn #####\\n")

391for response, chunk in chat.stream():391for response, chunk in chat.stream():

392 print(chunk.content, end="", flush=True)392 print(chunk.content, end="", flush=True)


409 409 

410### Append the Encrypted Agentic Tool Calling States410### Append the Encrypted Agentic Tool Calling States

411 411 

412There is another option for the ZDR (Zero Data Retention) users, or the users who don't want to use the above option, that is to let the SpaceXAI server also return412There is another option for the ZDR (Zero Data Retention) users, or the users who don't want to use the above option, that is to let the SpaceXSI server also return

413the encrypted reasoning and the encrypted tool output besides the final content to the client side, and those encrypted contents can be included as a part of the context413the encrypted reasoning and the encrypted tool output besides the final content to the client side, and those encrypted contents can be included as a part of the context

414in the next turn conversation.414in the next turn conversation.

415 415 


431 tools=[web_search(), x_search()],431 tools=[web_search(), x_search()],

432 use_encrypted_content=True,432 use_encrypted_content=True,

433)433)

434chat.append(user("What is xAI?"))434chat.append(user("What is SpaceXSI?"))

435print("\\n\\n##### First turn #####\\n")435print("\\n\\n##### First turn #####\\n")

436for response, chunk in chat.stream():436for response, chunk in chat.stream():

437 print(chunk.content, end="", flush=True)437 print(chunk.content, end="", flush=True)


518 input=[518 input=[

519 {519 {

520 "role": "user",520 "role": "user",

521 "content": "what is the latest update from xAI?",521 "content": "what is the latest update from SpaceXSI?",

522 },522 },

523 ],523 ],

524 tools=[524 tools=[


548 "input": [548 "input": [

549 {549 {

550 "role": "user",550 "role": "user",

551 "content": "what is the latest update from xAI?"551 "content": "what is the latest update from SpaceXSI?"

552 }552 }

553 ],553 ],

554 "tools": [554 "tools": [


573 "input": [573 "input": [

574 {574 {

575 "role": "user",575 "role": "user",

576 "content": "What is the latest update from xAI?"576 "content": "What is the latest update from SpaceXSI?"

577 }577 }

578 ],578 ],

579 "tools": [579 "tools": [


604 include=["verbose_streaming"],604 include=["verbose_streaming"],

605)605)

606 606 

607chat.append(user("what is the latest update from xAI?"))607chat.append(user("what is the latest update from SpaceXSI?"))

608 608 

609is_thinking = True609is_thinking = True

610for response, chunk in chat.stream():610for response, chunk in chat.stream():

Details

328from xai_sdk.tools import web_search, x_search328from xai_sdk.tools import web_search, x_search

329 329 

330tools = [330tools = [

331 web_search(), # Built-in: runs on xAI servers331 web_search(), # Built-in: runs on SpaceXSI servers

332 x_search(), # Built-in: runs on xAI servers332 x_search(), # Built-in: runs on SpaceXSI servers

333 tool( # Custom: runs on your side333 tool( # Custom: runs on your side

334 name="save_to_database",334 name="save_to_database",

335 description="Save research results to the database",335 description="Save research results to the database",


351 351 

352When mixing tools:352When mixing tools:

353 353 

354* **Built-in tools** execute automatically on SpaceXAI servers354* **Built-in tools** execute automatically on SpaceXSI servers

355* **Custom tools** pause execution and return to you for handling355* **Custom tools** pause execution and return to you for handling

356 356 

357See [Advanced Usage](/developers/tools/advanced-usage#mixing-server-side-and-client-side-tools) for complete examples with tool loops.357See [Advanced Usage](/developers/tools/advanced-usage#mixing-server-side-and-client-side-tools) for complete examples with tool loops.

Details

10 10 

11| Type | Description | Examples |11| Type | Description | Examples |

12|------|-------------|----------|12|------|-------------|----------|

13| **Built-in Tools** | Server-side tools managed by SpaceXAI that execute automatically | Web Search, X Search, Code Interpreter, Image Generation, Collections Search |13| **Built-in Tools** | Server-side tools managed by SpaceXSI that execute automatically | Web Search, X Search, Code Interpreter, Image Generation, Collections Search |

14| **Function Calling** | Custom functions you define that the model can invoke | Database queries, API calls, custom business logic |14| **Function Calling** | Custom functions you define that the model can invoke | Database queries, API calls, custom business logic |

15 15 

16Built-in tools run on SpaceXAI's servers—you provide the tool configuration, and the API handles execution and returns results. Function calling lets you define your own tools that the model can request, giving you full control over what happens when they're invoked.16Built-in tools run on SpaceXSI's servers—you provide the tool configuration, and the API handles execution and returns results. Function calling lets you define your own tools that the model can request, giving you full control over what happens when they're invoked.

17 17 

18## Pricing18## Pricing

19 19 


39 39 

40const { fullStream } = streamText({40const { fullStream } = streamText({

41 model: xai.responses('grok-4.7'),41 model: xai.responses('grok-4.7'),

42 prompt: 'What are the latest updates from xAI?',42 prompt: 'What are the latest updates from SpaceXSI?',

43 tools: {43 tools: {

44 web_search: xai.tools.webSearch(),44 web_search: xai.tools.webSearch(),

45 x_search: xai.tools.xSearch(),45 x_search: xai.tools.xSearch(),


68response = client.responses.create(68response = client.responses.create(

69 model="grok-4.7",69 model="grok-4.7",

70 input=[70 input=[

71 {"role": "user", "content": "What are the latest updates from xAI?"}71 {"role": "user", "content": "What are the latest updates from SpaceXSI?"}

72 ],72 ],

73 tools=[73 tools=[

74 {"type": "web_search"},74 {"type": "web_search"},


93 "input": [93 "input": [

94 {94 {

95 "role": "user",95 "role": "user",

96 "content": "What are the latest updates from xAI?"96 "content": "What are the latest updates from SpaceXSI?"

97 }97 }

98 ],98 ],

99 "tools": [99 "tools": [


115const stream = await client.responses.create({115const stream = await client.responses.create({

116 model: "grok-4.7",116 model: "grok-4.7",

117 input: [117 input: [

118 { role: "user", content: "What are the latest updates from xAI?" }118 { role: "user", content: "What are the latest updates from SpaceXSI?" }

119 ],119 ],

120 tools: [120 tools: [

121 { type: "web_search" },121 { type: "web_search" },


149 ],149 ],

150)150)

151 151 

152chat.append(user("What are the latest updates from xAI?"))152chat.append(user("What are the latest updates from SpaceXSI?"))

153 153 

154for response, chunk in chat.stream():154for response, chunk in chat.stream():

155 if chunk.content:155 if chunk.content:

Details

2 2 

3# Remote MCP Tools3# Remote MCP Tools

4 4 

5Remote MCP Tools allow Grok to connect to external MCP (Model Context Protocol) servers, extending its capabilities with custom tools from third parties or your own implementations. Simply specify a server URL and optional configuration - SpaceXAI manages the MCP server connection and interaction on your behalf.5Remote MCP Tools allow Grok to connect to external MCP (Model Context Protocol) servers, extending its capabilities with custom tools from third parties or your own implementations. Simply specify a server URL and optional configuration - SpaceXSI manages the MCP server connection and interaction on your behalf.

6 6 

7## SDK Support7## SDK Support

8 8 

Details

20 20 

21const { fullStream } = streamText({21const { fullStream } = streamText({

22 model: xai.responses('grok-4.7'),22 model: xai.responses('grok-4.7'),

23 prompt: 'What are the latest updates from xAI?',23 prompt: 'What are the latest updates from SpaceXSI?',

24 tools: {24 tools: {

25 web_search: xai.tools.webSearch(),25 web_search: xai.tools.webSearch(),

26 x_search: xai.tools.xSearch(),26 x_search: xai.tools.xSearch(),


57 include=["verbose_streaming"],57 include=["verbose_streaming"],

58)58)

59 59 

60chat.append(user("What are the latest updates from xAI?"))60chat.append(user("What are the latest updates from SpaceXSI?"))

61 61 

62is_thinking = True62is_thinking = True

63for response, chunk in chat.stream():63for response, chunk in chat.stream():


86// Synchronous request - waits for complete response86// Synchronous request - waits for complete response

87const { text, sources } = await generateText({87const { text, sources } = await generateText({

88 model: xai.responses('grok-4.7'),88 model: xai.responses('grok-4.7'),

89 prompt: 'What is the latest update from xAI?',89 prompt: 'What is the latest update from SpaceXSI?',

90 tools: {90 tools: {

91 web_search: xai.tools.webSearch(),91 web_search: xai.tools.webSearch(),

92 x_search: xai.tools.xSearch(),92 x_search: xai.tools.xSearch(),


118 ],118 ],

119)119)

120 120 

121chat.append(user("What is the latest update from xAI?"))121chat.append(user("What is the latest update from SpaceXSI?"))

122 122 

123# Get the final response in one go once it's ready123# Get the final response in one go once it's ready

124response = chat.sample()124response = chat.sample()


155 input=[155 input=[

156 {156 {

157 "role": "user",157 "role": "user",

158 "content": "what is the latest update from xAI?",158 "content": "what is the latest update from SpaceXSI?",

159 },159 },

160 ],160 ],

161 tools=[161 tools=[


180 "input": [180 "input": [

181 {181 {

182 "role": "user",182 "role": "user",

183 "content": "what is the latest update from xAI?"183 "content": "what is the latest update from SpaceXSI?"

184 }184 }

185 ],185 ],

186 "tools": [186 "tools": [


211 ],211 ],

212)212)

213 213 

214chat.append(user("What is the latest update from xAI?"))214chat.append(user("What is the latest update from SpaceXSI?"))

215response = chat.sample()215response = chat.sample()

216 216 

217print(response.content)217print(response.content)

Details

134 max_turns=3, # Limit to 3 assistant/tool-call turns134 max_turns=3, # Limit to 3 assistant/tool-call turns

135)135)

136 136 

137chat.append(user("What is the latest news from SpaceXAI?"))137chat.append(user("What is the latest news from SpaceXSI?"))

138response = chat.sample()138response = chat.sample()

139print(response.content)139print(response.content)

140```140```


169| Tool call types | Description |169| Tool call types | Description |

170|---------------|-------------|170|---------------|-------------|

171| `"client_side_tool"` | Client-side tool call - requires local execution |171| `"client_side_tool"` | Client-side tool call - requires local execution |

172| `"web_search_tool"` | Web-search tool - handled by SpaceXAI server |172| `"web_search_tool"` | Web-search tool - handled by SpaceXSI server |

173| `"x_search_tool"` | X-search tool - handled by SpaceXAI server |173| `"x_search_tool"` | X-search tool - handled by SpaceXSI server |

174| `"code_execution_tool"` | Code-execution tool - handled by SpaceXAI server |174| `"code_execution_tool"` | Code-execution tool - handled by SpaceXSI server |

175| `"collections_search_tool"` | Collections-search tool - handled by SpaceXAI server |175| `"collections_search_tool"` | Collections-search tool - handled by SpaceXSI server |

176| `"mcp_tool"` | MCP tool - handled by SpaceXAI server |176| `"mcp_tool"` | MCP tool - handled by SpaceXSI server |

177 177 

178### Using Responses API178### Using Responses API

179 179 


182| Types | Description |182| Types | Description |

183|-------|-------------|183|-------|-------------|

184| `"function_call"` | Client-side tool - requires local execution |184| `"function_call"` | Client-side tool - requires local execution |

185| `"web_search_call"` | Web-search tool - handled by SpaceXAI server |185| `"web_search_call"` | Web-search tool - handled by SpaceXSI server |

186| `"custom_tool_call"` | X-search tool when `call_id` starts with `xs_` (attachment search uses `as_`) - handled by SpaceXAI server |186| `"custom_tool_call"` | X-search tool when `call_id` starts with `xs_` (attachment search uses `as_`) - handled by SpaceXSI server |

187| `"code_interpreter_call"` | Code-execution tool - handled by SpaceXAI server |187| `"code_interpreter_call"` | Code-execution tool - handled by SpaceXSI server |

188| `"file_search_call"` | Collections-search tool - handled by SpaceXAI server |188| `"file_search_call"` | Collections-search tool - handled by SpaceXSI server |

189| `"mcp_call"` | MCP tool - handled by SpaceXAI server |189| `"mcp_call"` | MCP tool - handled by SpaceXSI server |