SpyBara
Go Premium

Documentation 2026-11-12 22:57 UTC to 2026-11-13 23:58 UTC

131 files changed +1,730 −2,074. View all changes and history on the product overview
2026
Fri 13 23:58 Thu 12 22:57 Wed 11 23:57 Tue 10 23:02 Mon 9 23:02 Sun 8 22:59 Sat 7 22:59 Fri 6 23:00 Thu 5 23:00 Wed 4 22:58 Tue 3 22:58 Mon 2 23:58 Sun 1 23:00
Details

144 144 

145 145 

146 146 

147#### JavaScript147#### TypeScript

148 148 

149 149 

150 150 

151#### Thread object (JavaScript)151#### Thread object (TypeScript)

152 152 

153```javascript153```typescript

154import OpenAI from "openai";154import OpenAI from "openai";

155 155 

156const client = new OpenAI();156const client = new OpenAI();


161console.log(thread.id);161console.log(thread.id);

162```162```

163 163 

164#### Conversation object (JavaScript)164#### Conversation object (TypeScript)

165 165 

166```javascript166```typescript

167import OpenAI from "openai";167import OpenAI from "openai";

168 168 

169const client = new OpenAI();169const client = new OpenAI();


305 305 

306 306 

307 307 

308#### JavaScript308#### TypeScript

309 309 

310 310 

311 311 

312#### Run object (JavaScript)312#### Run object (TypeScript)

313 313 

314```javascript314```typescript

315import { setTimeout } from "node:timers/promises";315import { setTimeout } from "node:timers/promises";

316import OpenAI from "openai";316import OpenAI from "openai";

317 317 


331console.log(run.status);331console.log(run.status);

332```332```

333 333 

334#### Response object (JavaScript)334#### Response object (TypeScript)

335 335 

336```javascript336```typescript

337// Replace the illustrative IDs and URLs below with your own resource values.337// Replace the illustrative IDs and URLs below with your own resource values.

338import OpenAI from "openai";338import OpenAI from "openai";

339 339 


685 685

686Responses API686Responses API

687 687 

688```javascript688```typescript

689// Replace the illustrative IDs and URLs below with your own resource values.689// Replace the illustrative IDs and URLs below with your own resource values.

690import express from "express";690import express from "express";

691import OpenAI from "openai";691import OpenAI from "openai";

692 692 

693const app = express();693const app = express();

694const client = new OpenAI();694const client = new OpenAI();

695const conversationsBySession = new Map();695const conversationsBySession = new Map<string, Promise<string>>();

696 696 

697app.use(express.json());697app.use(express.json());

698 698 

deprecations.md +202 −513

Details

4 4 

5## Overview5## Overview

6 6 

7As we launch safer and more capable models, we regularly retire older models. Software relying on OpenAI models may need occasional updates to keep working. Impacted customers will always be notified by email and in our documentation along with [blog posts](https://openai.com/blog) for larger changes.7As we launch safer and more capable models, we regularly retire older models. Software relying on OpenAI models may need occasional updates to keep working. Impacted customers will always be notified by email and in our documentation.

8 8 

9This page lists all API deprecations, along with recommended replacements.9Each model has one of three lifecycle states.

10 10 

11To monitor model shutdowns programmatically, call the [List models endpoint](https://developers.openai.com/api/reference/resources/models/methods/list) (`GET /v1/models`) and check each model's optional `shutdown_date` field. When present, this field contains the shutdown date as a `YYYY-MM-DD` string, or `null` if no shutdown date has been announced; the field is also available from the [Retrieve a model endpoint](https://developers.openai.com/api/reference/resources/models/methods/retrieve).11- **Active.** You can use the model through the API. OpenAI hasn't announced its retirement.

12- **Deprecated.** OpenAI has announced the model's retirement. You can still use it until its shutdown date.

13- **Shutdown.** The model no longer accepts requests through the standard API.

12 14 

13## Model deprecation notice periods15For deprecation notice periods and help migrating to a replacement model, see the [deprecation policy](#model-deprecation-notice-periods) and [migration guidance](#migration-guidance) below.

14 

15We provide advance notice before retiring models so customers have time to plan and migrate. When we announce a model deprecation, we notify customers who are actively using the model by email and document the deprecation on this page.

16 

17Unless safety or compliance concerns require a faster timeline, we provide the following minimum notice periods before model retirement:

18 16 

19- **Generally available models:** At least 6 months.17See [feature and endpoint deprecations](#feature-and-endpoint-deprecations) for other upcoming API shutdowns.

20- **Specialized variants of generally available models and image generation models:** At least 3 months. Examples include chat variants such as `gpt-5.1-chat-latest`, Codex variants such as `gpt-5.3-codex`, and deep research variants such as `o3-deep-research`.

21- **Preview models:** Preview models, identified by `preview` in the model name, may be retired with much shorter notice, such as 2 weeks. Examples include `computer-use-preview` and `gpt-4o-audio-preview`. We don't recommend using preview models for business-critical production workloads unless you can migrate on short notice.

22 

23If safety or compliance concerns require us to retire a model sooner, we will provide as much notice as reasonably possible.

24 

25These notice periods give customers time to evaluate recommended replacement models, test application behavior, and complete migrations before a model is no longer available. In some cases, developers may be able to provision dedicated capacity for continued access after a model's shutdown date. To explore this option, [contact our sales team](https://openai.com/contact-sales/).

26 

27## Deprecation vs. legacy

28 

29We use the term "deprecation" to refer to the process of retiring a model or endpoint. When we announce that a model or endpoint is being deprecated, it immediately becomes deprecated. All deprecated models and endpoints will also have a shut down date. At the time of the shut down, the model or endpoint will no longer be accessible.

30 

31We use the terms "sunset" and "shut down" interchangeably to mean a model or endpoint is no longer accessible.

32 

33We use the term "legacy" to refer to models and endpoints that no longer receive updates. We tag endpoints and models as legacy to signal to developers where we're moving as a platform and that they should likely migrate to newer models or endpoints. You can expect that a legacy model or endpoint will be deprecated at some point in the future.

34 18 

35## Upcoming deprecations19## Upcoming deprecations

36 20 

37Upcoming deprecations are listed below, with the most recent announcements at the top.

38 

39### 2026-11-10: GPT Image 2

40 21 

41The `gpt-image-2` model and `gpt-image-2-2026-04-21` snapshot are deprecated and will be removed from the API on February 10, 2027.

42 22 

43| Shutdown date | Model / system | Recommended replacement |

44| ----------------- | ----------------------------------------- | ------------------------------------------------- |

45| February 10, 2027 | `gpt-image-2` \| `gpt-image-2-2026-04-21` | `gpt-image-2.6-sunburst` or `gpt-image-2.6-flare` |

46 23 

47### 2026-11-05: GPT-5.5-Cyber24| Shutdown date | Affected model | Status | Recommended replacement | Notice date |

25| ---------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------- | ------------ |

26| **Dec 1, 2026** | `gpt-image-1-mini` | Deprecated | `gpt-image-2.6-sunburst` or `gpt-image-2.6-flare` | Jun 2, 2026 |

27| **Dec 1, 2026** | `gpt-image-1.5`, `gpt-image-1.5-2025-12-16` | Deprecated | `gpt-image-2.6-sunburst` or `gpt-image-2.6-flare` | Jun 2, 2026 |

28| **Dec 1, 2026** | `chatgpt-image-latest` | Deprecated | `gpt-image-2.6-sunburst` or `gpt-image-2.6-flare` | Jun 2, 2026 |

29| **Dec 11, 2026** | `gpt-5`, `gpt-5-2025-08-07` | Deprecated | `gpt-6.1-sol` | Jun 11, 2026 |

30| **Dec 11, 2026** | `gpt-5-mini`, `gpt-5-mini-2025-08-07` | Deprecated | `gpt-6.1-terra` | Jun 11, 2026 |

31| **Dec 11, 2026** | `gpt-5-nano`, `gpt-5-nano-2025-08-07` | Deprecated | `gpt-6-luna` | Jun 11, 2026 |

32| **Dec 11, 2026** | `gpt-5-pro`, `gpt-5-pro-2025-10-06` | Deprecated | `gpt-6.1-sol` (`reasoning.mode: pro`) in the Responses API | Jun 11, 2026 |

33| **Dec 11, 2026** | `o3`, `o3-2025-04-16` | Deprecated | `gpt-6.1-sol` | Jun 11, 2026 |

34| **Dec 11, 2026** | `o3-pro`, `o3-pro-2025-06-10` | Deprecated | `gpt-6.1-sol` (`reasoning.mode: pro`) in the Responses API | Jun 11, 2026 |

35| **Jan 6, 2027** | `tts-1` | Deprecated | `gpt-realtime-2.1-mini` | Oct 1, 2026 |

36| **Jan 6, 2027** | `tts-1-hd` | Deprecated | `gpt-realtime-2.1-mini` | Oct 1, 2026 |

37| **Jan 6, 2027** | `gpt-4o-mini-tts`, `gpt-4o-mini-tts-2025-03-20`, `gpt-4o-mini-tts-2025-12-15` | Deprecated | `gpt-realtime-2.1-mini` | Oct 1, 2026 |

38| **Jan 14, 2027** | GPT-4o (`gpt-4o-2024-08-06`, `gpt-4o-2024-11-20`) | Deprecated | `gpt-6-luna` | Oct 14, 2026 |

39| **Jan 14, 2027** | GPT-4o mini (`gpt-4o-mini-2024-07-18`) | Deprecated | `gpt-6-luna` | Oct 14, 2026 |

40| **Jan 14, 2027** | GPT-4.1 (`gpt-4.1-2025-04-14`) | Deprecated | `gpt-6-luna` | Oct 14, 2026 |

41| **Jan 14, 2027** | GPT-4.1 mini (`gpt-4.1-mini-2025-04-14`) | Deprecated | `gpt-6-luna` | Oct 14, 2026 |

42| **Jan 20, 2027** | `gpt-realtime`, `gpt-realtime-2025-08-28` | Deprecated | `gpt-realtime-2.1` | Jul 20, 2026 |

43| **Jan 20, 2027** | `gpt-audio`, `gpt-audio-2025-08-28` | Deprecated | `gpt-audio-1.5` | Jul 20, 2026 |

44| **Jan 20, 2027** | `gpt-4o-audio` | Deprecated | `gpt-audio-1.5` | Jul 20, 2026 |

45| **Jan 20, 2027** | `gpt-4o-realtime` | Deprecated | `gpt-realtime-2.1` | Jul 20, 2026 |

46| **Jan 20, 2027** | `gpt-realtime-mini`, `gpt-realtime-mini-2025-12-15` | Deprecated | `gpt-realtime-2.1-mini` | Jul 20, 2026 |

47| **Jan 20, 2027** | `gpt-audio-mini`, `gpt-audio-mini-2025-12-15` | Deprecated | `gpt-audio-1.5` | Jul 20, 2026 |

48| **Jan 20, 2027** | `gpt-4o-mini-realtime` | Deprecated | `gpt-realtime-2.1-mini` | Jul 20, 2026 |

49| **Jan 20, 2027** | `gpt-4o-mini-audio` | Deprecated | `gpt-audio-1.5` | Jul 20, 2026 |

50| **Jan 20, 2027** | `gpt-4o-mini-transcribe-2025-03-20` | Deprecated | `gpt-4o-mini-transcribe-2025-12-15` | Jul 20, 2026 |

51| **Feb 1, 2027** | `gpt-5.5-cyber-preview` | Deprecated | The most capable cyber model available to you. | Nov 5, 2026 |

52| **Feb 10, 2027** | `gpt-image-2`, `gpt-image-2-2026-04-21` | Deprecated | `gpt-image-2.6-sunburst` or `gpt-image-2.6-flare` | Nov 10, 2026 |

53| **Feb 26, 2027** | `whisper-1` | Deprecated | `gpt-live-transcribe` or `gpt-transcribe` | Aug 26, 2026 |

54| **Feb 26, 2027** | `gpt-4o-transcribe` | Deprecated | `gpt-live-transcribe` or `gpt-transcribe` | Aug 26, 2026 |

55| **Feb 26, 2027** | `gpt-4o-mini-transcribe`, `gpt-4o-mini-transcribe-2025-12-15` | Deprecated | `gpt-live-transcribe` or `gpt-transcribe` | Aug 26, 2026 |

56| **Feb 26, 2027** | `gpt-4o-transcribe-diarize` | Deprecated | `gpt-live-transcribe` or `gpt-transcribe` | Aug 26, 2026 |

57| **Apr 1, 2027** | `gpt-5.3-codex` | Deprecated | `gpt-6-sol` | Oct 1, 2026 |

58| **Apr 1, 2027** | `gpt-5.4-nano`, `gpt-5.4-nano-2026-03-17` | Deprecated | `gpt-6-luna` | Oct 1, 2026 |

59| **Apr 1, 2027** | `gpt-5.1`, `gpt-5.1-2025-11-13` | Deprecated | `gpt-6-sol` | Oct 1, 2026 |

48 60 

49The `gpt-5.5-cyber-preview` model is deprecated and will be removed from the API on February 1, 2027. Migrate to the most capable cyber model available to you before the shutdown date.

50 61 

51| Shutdown date | Model / system | Recommended replacement |

52| ---------------- | ----------------------- | ---------------------------------------------- |

53| February 1, 2027 | `gpt-5.5-cyber-preview` | The most capable cyber model available to you. |

54 62 

55### 2026-10-14: GPT-4 series model deprecations

56 63 

57On October 14, 2026, we notified developers using certain GPT-4 series models of their deprecation and removal from the API on January 14, 2027.64Fine-tuned versions of the models listed above follow the same shutdown schedule as their underlying base models.

58 65 

59| Shutdown date | Model / system | Recommended replacement |66For speech migrations, see the [Realtime API guide](https://developers.openai.com/api/docs/guides/realtime) and the [transcription guide](https://developers.openai.com/api/docs/guides/transcription).

60| ---------------- | ------------------------------------------------- | ----------------------- |

61| January 14, 2027 | GPT-4o (`gpt-4o-2024-08-06`, `gpt-4o-2024-11-20`) | `gpt-6-luna` |

62| January 14, 2027 | GPT-4o mini (`gpt-4o-mini-2024-07-18`) | `gpt-6-luna` |

63| January 14, 2027 | GPT-4.1 (`gpt-4.1-2025-04-14`) | `gpt-6-luna` |

64| January 14, 2027 | GPT-4.1 mini (`gpt-4.1-mini-2025-04-14`) | `gpt-6-luna` |

65 67 

66Fine-tuned versions of these models follow the same shutdown schedule as their underlying base models.68## Feature and endpoint deprecations

67 69 

68### 2026-10-01: GPT-5.3-Codex, GPT-5.1, GPT-5.4 nano

69 70 

70The following models are deprecated and will be removed from the API on April 1, 2027, with six months' notice. Migrate to the recommended replacements before the shutdown date.

71 71 

72| Shutdown date | Model / system | Recommended replacement |

73| ------------- | ------------------------------------------- | ----------------------- |

74| Apr 1, 2027 | `gpt-5.3-codex` | `gpt-6-sol` |

75| Apr 1, 2027 | `gpt-5.4-nano` \| `gpt-5.4-nano-2026-03-17` | `gpt-6-luna` |

76| Apr 1, 2027 | `gpt-5.1` \| `gpt-5.1-2025-11-13` | `gpt-6-sol` |

77 72 

78### 2026-10-01: Text-to-speech models73| Shutdown date | Affected feature or endpoint | Status | Recommended replacement | Notice date |

74| ---------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------ |

75| **Nov 30, 2026** | `/v1/prompts` and reusable prompt objects | Deprecated | Move prompt content into your application code. [Migration guide](https://developers.openai.com/api/docs/guides/prompting/migrate-from-prompt-object) | Jun 3, 2026 |

76| **Nov 30, 2026** | Evals dashboard, API, and graders for eval workflows | Read-only | [Migrate to Promptfoo](https://developers.openai.com/cookbook/examples/evaluation/moving-from-openai-evals-to-promptfoo). For fine-tuning graders, see the [fine-tuning timeline](#update-to-openais-self-serve-fine-tuning). | Jun 3, 2026 |

77| **Nov 30, 2026** | Agent Builder | Deprecated | Agents SDK or ChatGPT Workspace Agents. [Migration guide](https://developers.openai.com/api/docs/guides/agent-builder/migrate-from-agent-builder). ChatKit remains available. | Jun 3, 2026 |

78| **Jan 6, 2027** | Self-serve fine-tuning job creation | Restricted access | See the [fine-tuning timeline](#update-to-openais-self-serve-fine-tuning). | May 7, 2026 |

79| **Feb 26, 2027** | `/v1/audio/translations` | Deprecated | [`/v1/realtime/translations`](https://developers.openai.com/api/docs/guides/realtime-translation) | Aug 26, 2026 |

79 80 

80The following text-to-speech models are deprecated and will be removed from the API on January 6, 2027, with at least three months' notice. Migrate to `gpt-realtime-2.1-mini` before the shutdown date. See the [Realtime API guide](https://developers.openai.com/api/docs/guides/realtime) to plan your migration.

81 81 

82| Shutdown date | Model / system | Recommended replacement |

83| ------------- | ------------------------------------------------- | ----------------------- |

84| Jan 6, 2027 | `tts-1` | `gpt-realtime-2.1-mini` |

85| Jan 6, 2027 | `tts-1-hd` | `gpt-realtime-2.1-mini` |

86| Jan 6, 2027 | `gpt-4o-mini-tts` \| `gpt-4o-mini-tts-2025-03-20` | `gpt-realtime-2.1-mini` |

87| Jan 6, 2027 | `gpt-4o-mini-tts` \| `gpt-4o-mini-tts-2025-12-15` | `gpt-realtime-2.1-mini` |

88 

89### 2026-08-26: Transcription models

90 

91On August 26, 2026, we notified developers using `whisper-1`, `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, and `gpt-4o-transcribe-diarize` of their deprecation and removal from the API on February 26, 2027.

92 

93For information about the recommended replacements, see the [transcription guide](https://developers.openai.com/api/docs/guides/transcription).

94 

95| Shutdown date | Model / system | Recommended replacement |

96| ------------- | --------------------------------------------------------------- | ----------------------------------------- |

97| Feb 26, 2027 | `whisper-1` | `gpt-live-transcribe` or `gpt-transcribe` |

98| Feb 26, 2027 | `gpt-4o-transcribe` | `gpt-live-transcribe` or `gpt-transcribe` |

99| Feb 26, 2027 | `gpt-4o-mini-transcribe` \| `gpt-4o-mini-transcribe-2025-12-15` | `gpt-live-transcribe` or `gpt-transcribe` |

100| Feb 26, 2027 | `gpt-4o-transcribe-diarize` | `gpt-live-transcribe` or `gpt-transcribe` |

101| Feb 26, 2027 | `/v1/audio/translations` | `v1/realtime/translations` |

102 

103### 2026-07-20: Legacy audio, realtime, and transcription models

104 

105On July 20, 2026, we notified developers using legacy audio, realtime, and transcription model families and snapshots of their deprecation and removal from the API on January 20, 2027.

106 

107| Shutdown date | Model family / snapshot | Recommended replacement |

108| ------------- | ----------------------------------------------------- | ----------------------------------- |

109| Jan 20, 2027 | `gpt-realtime` \| `gpt-realtime-2025-08-28` | `gpt-realtime-2.1` |

110| Jan 20, 2027 | `gpt-audio` \| `gpt-audio-2025-08-28` | `gpt-audio-1.5` |

111| Jan 20, 2027 | `gpt-4o-audio` | `gpt-audio-1.5` |

112| Jan 20, 2027 | `gpt-4o-realtime` | `gpt-realtime-2.1` |

113| Jan 20, 2027 | `gpt-realtime-mini` \| `gpt-realtime-mini-2025-12-15` | `gpt-realtime-2.1-mini` |

114| Jan 20, 2027 | `gpt-audio-mini` \| `gpt-audio-mini-2025-12-15` | `gpt-audio-1.5` |

115| Jan 20, 2027 | `gpt-4o-mini-realtime` | `gpt-realtime-2.1-mini` |

116| Jan 20, 2027 | `gpt-4o-mini-audio` | `gpt-audio-1.5` |

117| Jan 20, 2027 | `gpt-4o-mini-transcribe-2025-03-20` | `gpt-4o-mini-transcribe-2025-12-15` |

118 

119### 2026-06-11: GPT-5 and o3 model deprecations

120 

121On June 11, 2026, we notified developers using older GPT-5 and o3 model snapshots of their deprecation and removal from the API on December 11, 2026.

122 

123| Shutdown date | Model / system | Recommended replacement |

124| ------------- | --------------------------------------- | ------------------------------------- |

125| Dec 11, 2026 | `gpt-5` \| `gpt-5-2025-08-07` | `gpt-5.6-sol` |

126| Dec 11, 2026 | `gpt-5-mini` \| `gpt-5-mini-2025-08-07` | `gpt-5.6-terra` |

127| Dec 11, 2026 | `gpt-5-nano` \| `gpt-5-nano-2025-08-07` | `gpt-5.6-luna` |

128| Dec 11, 2026 | `gpt-5-pro` \| `gpt-5-pro-2025-10-06` | `gpt-5.6-sol` (`reasoning.mode: pro`) |

129| Dec 11, 2026 | `o3` \| `o3-2025-04-16` | `gpt-5.6-sol` |

130| Dec 11, 2026 | `o3-pro` \| `o3-pro-2025-06-10` | `gpt-5.6-sol` (`reasoning.mode: pro`) |

131 

132Fine-tuned versions of these models follow the same shutdown schedule as their underlying base models.

133 

134### 2026-06-03: Reusable prompts

135 

136On June 3, 2026, we notified developers using reusable prompts in the dashboard and API that reusable prompt objects are being deprecated.

137 

138| Date | Update |

139| ------------ | ---------------------------------------------------------------------------- |

140| June 3, 2026 | Deprecation announced and prompt creation de-emphasized in the platform. |

141| Nov 30, 2026 | The `v1/prompts` API and reusable prompt objects are scheduled to shut down. |

142 82 

143To migrate, move reusable prompt content into your application code. See [Migrate from prompt objects](https://developers.openai.com/api/docs/guides/prompting/migrate-from-prompt-object).

144 83 

145### 2026-06-03: Evals platform84## Model deprecation notice periods

146 

147On June 3, 2026, we notified developers using the Evals platform that the product is being deprecated.

148 

149| Date | Update |

150| ------------ | ------------------------------------------------------- |

151| June 3, 2026 | Deprecation announced for the Evals platform. |

152| Oct 31, 2026 | Existing evals become read-only. |

153| Nov 30, 2026 | The Evals dashboard and API are scheduled to shut down. |

154 

155Graders documented for eval workflows are part of this transition. Fine-tuning-related timelines remain covered in the self-serve fine-tuning section below.

156 85 

157See [Moving from OpenAI Evals to Promptfoo](https://developers.openai.com/cookbook/examples/evaluation/moving-from-openai-evals-to-promptfoo) for a migration path.86We provide advance notice before retiring models so customers have time to plan and migrate. When we announce a model deprecation, we notify customers who are actively using the model by email and document the deprecation on this page.

158 87 

159### 2026-06-03: Agent Builder88Unless safety or compliance concerns require a faster timeline, we provide the following minimum notice periods before model retirement:

160 89 

161On June 3, 2026, we notified developers using Agent Builder that the product is being deprecated. ChatKit remains available.90- **Generally available models:** At least 6 months.

91- **Specialized variants of generally available models and image generation models:** At least 3 months. Examples include chat variants such as `gpt-5.1-chat-latest`, Codex variants such as `gpt-5.3-codex`, and deep research variants such as `o3-deep-research`.

92- **Preview models:** Preview models, identified by `preview` in the model name, may be retired with much shorter notice, such as 2 weeks. Examples include `computer-use-preview` and `gpt-4o-audio-preview`. We don't recommend using preview models for business-critical production workloads unless you can migrate on short notice.

162 93 

163| Date | Update |94These notice periods give customers time to evaluate recommended replacement models, test application behavior, and complete migrations before a model is no longer available. In some cases, developers may be able to provision **dedicated capacity for continued access** after a model's shutdown date. To explore this option, [contact our sales team](https://openai.com/contact-sales/).

164| ------------ | ---------------------------------------- |

165| June 3, 2026 | Deprecation announced for Agent Builder. |

166| Nov 30, 2026 | Agent Builder is scheduled to shut down. |

167 95 

168See [Migrate from Agent Builder](https://developers.openai.com/api/docs/guides/agent-builder/migrate-from-agent-builder) to continue with the Agents SDK or ChatGPT Workspace Agents.96## Best practices

169 97 

170### 2026-06-02: GPT Image model deprecations98- Check **the documentation** regularly for model deprecation updates.

99- To monitor model shutdowns **programmatically**, call the [List models endpoint](https://developers.openai.com/api/reference/resources/models/methods/list) (`GET /v1/models`) and check each model's optional `shutdown_date` field. The field is also available from the [Retrieve a model endpoint](https://developers.openai.com/api/reference/resources/models/methods/retrieve).

171 100 

172On June 2, 2026, we notified developers using older GPT Image models of their deprecation and removal from the API on December 1, 2026.101## Migration guidance

173 102 

174| Shutdown date | Model / system | Recommended replacement |103- In Codex, invoke the [OpenAI Docs skill](https://github.com/openai/codex/tree/main/codex-rs/skills/src/assets/samples/openai-docs) with `$openai-docs` and ask it to migrate your project to the recommended replacement.

175| ------------- | --------------------------------------------- | ------------------------------------------------- |104- See the [**GPT-6 migration guide**](https://developers.openai.com/api/docs/guides/latest-model#gpt-6-astra-migration-quickstart).

176| Dec 1, 2026 | `gpt-image-1-mini` | `gpt-image-2.6-sunburst` or `gpt-image-2.6-flare` |105- Run representative requests against both models. Compare outputs, latency, and cost before switching production traffic to the replacement.

177| Dec 1, 2026 | `gpt-image-1.5` \| `gpt-image-1.5-2025-12-16` | `gpt-image-2.6-sunburst` or `gpt-image-2.6-flare` |

178| Dec 1, 2026 | `chatgpt-image-latest` | `gpt-image-2.6-sunburst` or `gpt-image-2.6-flare` |

179 106 

180### Update to OpenAI’s self-serve fine-tuning107## Update to OpenAI’s self-serve fine-tuning

181 108 

182On May 7th, 2026, we notified developers using OpenAI’s self-serve fine-tuning platform of updates to availability.109On May 7th, 2026, we notified developers using OpenAI’s self-serve fine-tuning platform of updates to availability.

183 110 


189| July 2, 2026 | Creating fine-tuning jobs is no longer available to organizations that have not run inference on a fine-tuned model in the past 60 days. |116| July 2, 2026 | Creating fine-tuning jobs is no longer available to organizations that have not run inference on a fine-tuned model in the past 60 days. |

190| Jan 6, 2027 | Active existing customers will no longer be able to create new fine-tuning jobs on this date. Inference on fine-tuned models will be disabled only when the underlying base model is deprecated. |117| Jan 6, 2027 | Active existing customers will no longer be able to create new fine-tuning jobs on this date. Inference on fine-tuned models will be disabled only when the underlying base model is deprecated. |

191 118 

192## Past deprecations

193 

194Past deprecations are listed below, with the most recent announcements at the top.

195 

196### 2026-09-11: GPT-5.4-Cyber

197 

198The `gpt-5.4-cyber` model is deprecated and will be removed from the API on October 1, 2026. Migrate to the most capable cyber model available to you before the shutdown date.

199 

200| Shutdown date | Model / system | Recommended replacement |

201| ------------- | --------------- | ---------------------------------------------- |

202| Oct 1, 2026 | `gpt-5.4-cyber` | The most capable cyber model available to you. |

203 

204### 2026-05-08: `gpt-5.2-chat-latest` and `gpt-5.3-chat-latest` model snapshots

205 

206On May 8th, 2026, we notified developers using `gpt-5.2-chat-latest` and `gpt-5.3-chat-latest` model snapshots of their deprecation and removal from the API.

207 

208| Shutdown date | Model / system | Recommended replacement |

209| ------------- | --------------------- | ----------------------- |

210| Aug 10, 2026 | `gpt-5.2-chat-latest` | `gpt-5.6-sol` |

211| Aug 10, 2026 | `gpt-5.3-chat-latest` | `gpt-5.6-sol` |

212 

213### 2026-04-22: Legacy GPT model snapshots

214 

215On April 22, 2026, we announced the deprecation of the following older OpenAI models. Access to these models was shut down on October 23, 2026.

216 

217| Shutdown date | Model snapshot | Substitute model |

218| ---------------- | ---------------------------------------------------------------------- | ------------------------------------------------- |

219| October 23, 2026 | `gpt-3.5-turbo-0125` \| `gpt-3.5-turbo`, `gpt-3.5-turbo-completions` | `gpt-5.6-terra` |

220| October 23, 2026 | `gpt-4-0613` \| `gpt-4`, `gpt-4-0613-completions`, `gpt-4-completions` | `gpt-5.6-sol` |

221| October 23, 2026 | `gpt-4-1106-preview` | `gpt-5.6-sol` |

222| October 23, 2026 | `gpt-4-turbo` \| `gpt-4-turbo-2024-04-09`, `gpt-4-turbo-completions` | `gpt-5.6-sol` |

223| October 23, 2026 | `gpt-4.1-nano` \| `gpt-4.1-nano-2025-04-14` | `gpt-5.6-luna` |

224| October 23, 2026 | `gpt-4o-2024-05-13` | `gpt-5.6-sol` |

225| October 23, 2026 | `gpt-image-1` | `gpt-image-2.5-sunburst` or `gpt-image-2.5-flare` |

226| October 23, 2026 | `o1-2024-12-17` \| `o1` | `gpt-5.6-sol` |

227| October 23, 2026 | `o1-pro-2025-03-19` \| `o1-pro` | `gpt-5.6-sol` (`reasoning.mode: pro`) |

228| October 23, 2026 | `o3-mini-2025-01-31` \| `o3-mini` | `gpt-5.6-sol` |

229| October 23, 2026 | `ft-o4-mini-2025-04-16` | `gpt-5.6-terra` |

230| October 23, 2026 | `o4-mini-2025-04-16` \| `o4-mini` | `gpt-5.6-terra` |

231 

232Fine-tuned versions of these models follow the same shutdown schedule as their underlying base models.

233 

234### 2026-04-22: Legacy GPT model snapshots (July 2026 shutdown)

235 

236On April 22, 2026, we announced the deprecation of the following older OpenAI models. Access to these models was shut down on July 23, 2026.

237 

238| Shutdown date | Model snapshot | Substitute model |

239| ------------- | ------------------------------------------------------------- | ----------------------- |

240| July 23, 2026 | `computer-use-preview-2025-03-11` \| `computer-use-preview` | `gpt-5.6-terra` |

241| July 23, 2026 | `gpt-4o-mini-search-preview-2025-03-11` | `gpt-5.6-terra` |

242| July 23, 2026 | `gpt-4o-search-preview-2025-03-11` | `gpt-5.6-terra` |

243| July 23, 2026 | `gpt-5-chat-latest` | `gpt-5.6-sol` |

244| July 23, 2026 | `gpt-5-codex` | `gpt-5.6-sol` |

245| July 23, 2026 | `gpt-5.1-chat-latest` | `gpt-5.6-sol` |

246| July 23, 2026 | `gpt-5.1-codex` | `gpt-5.6-sol` |

247| July 23, 2026 | `gpt-5.1-codex-max` | `gpt-5.6-sol` |

248| July 23, 2026 | `gpt-5.1-codex-mini` | `gpt-5.6-terra` |

249| July 23, 2026 | `gpt-audio-mini-2025-10-06` | `gpt-audio-1.5` |

250| July 23, 2026 | `gpt-realtime-mini-2025-10-06` | `gpt-realtime-2.1-mini` |

251| July 23, 2026 | `o3-deep-research-2025-06-26` \| `o3-deep-research` | `gpt-5.6-sol` |

252| July 23, 2026 | `o4-mini-deep-research-2025-06-26` \| `o4-mini-deep-research` | `gpt-5.6-sol` |

253| July 23, 2026 | `gpt-5.2-codex` | `gpt-5.6-sol` |

254 

255### 2026-03-24: Sora 2 video generation models and Videos API

256 

257On March 24th, 2026, we notified developers using the Videos API and Sora 2 video generation model aliases and snapshots of their deprecation and removal from the API on September 24, 2026.

258 

259| Shutdown date | Model / system | Recommended replacement |

260| ------------- | ----------------------- | ----------------------- |

261| 2026-09-24 | Videos API | --- |

262| 2026-09-24 | `sora-2` | --- |

263| 2026-09-24 | `sora-2-pro` | --- |

264| 2026-09-24 | `sora-2-2025-10-06` | --- |

265| 2026-09-24 | `sora-2-2025-12-08` | --- |

266| 2026-09-24 | `sora-2-pro-2025-10-06` | --- |

267 119 

268### 2025-11-18: `chatgpt-4o-latest` snapshot

269 120 

270On November 18th, 2025, we notified developers using `chatgpt-4o-latest` model snapshot of its deprecation and removal from the API on February 17, 2026.121<a id="past-deprecations"></a>

271 122 

272| Shutdown date | Model / system | Recommended replacement |

273| ------------- | ------------------- | ----------------------- |

274| 2026-02-17 | `chatgpt-4o-latest` | `gpt-5.1-chat-latest` |

275 123 

276### 2025-11-17: `codex-mini-latest` model snapshot

277 124 

278On November 17th, 2025, we notified developers using `codex-mini-latest` model of its deprecation and removal from the API on February 12, 2026. As part of this deprecation, we will no longer support our legacy local shell tool, which is only available for use with `codex-mini-latest`. For new use cases, please use our latest shell tool.125## Past deprecations

279 

280| Shutdown date | Model / system | Recommended replacement |

281| ------------- | ------------------- | ----------------------- |

282| 2026-02-12 | `codex-mini-latest` | `gpt-5-codex-mini` |

283 

284### 2025-11-14: DALL·E model snapshots

285 

286On November 14th, 2025, we notified developers using DALL·E model snapshots of their deprecation and removal from the API on May 12, 2026.

287 

288| Shutdown date | Model / system | Recommended replacement |

289| ------------- | -------------- | --------------------------------------------------- |

290| 2026-05-12 | `dall-e-2` | `gpt-image-2`, `gpt-image-1`, or `gpt-image-1-mini` |

291| 2026-05-12 | `dall-e-3` | `gpt-image-2`, `gpt-image-1`, or `gpt-image-1-mini` |

292 

293### 2025-09-26: Legacy GPT model snapshots

294 

295To improve reliability and make it easier for developers to choose the right models, we deprecated a set of older OpenAI models with declining usage. Access to these models was shut down on September 28, 2026.

296 

297| Shutdown date | Model / system | Recommended replacement |

298| ------------- | ------------------------ | ----------------------- |

299| 2026-09-28 | `gpt-3.5-turbo-instruct` | `gpt-5.6-terra` |

300| 2026-09-28 | `babbage-002` | `gpt-5.6-terra` |

301| 2026-09-28 | `davinci-002` | `gpt-5.6-terra` |

302| 2026-09-28 | `gpt-3.5-turbo-1106` | `gpt-5.6-terra` |

303 

304### 2025-09-26: Legacy GPT model snapshots (March 2026 shutdown)

305 

306To improve reliability and make it easier for developers to choose the right models, we deprecated a set of older OpenAI models with declining usage. Access to these models was shut down on March 26, 2026.

307 

308| Shutdown date | Model / system | Recommended replacement |

309| ------------- | -------------------------------------------------------------------------------------------------------------------------- | ----------------------- |

310| 2026‑03‑26 | `gpt-4-0314` | `gpt-5` or `gpt-4.1*` |

311| 2026‑03‑26 | `gpt-4-0125-preview` (including `gpt-4-turbo-preview` and `gpt-4-turbo-preview-completions`, which point to this snapshot) | `gpt-5` or `gpt-4.1*` |

312 

313\*For tasks that are especially latency sensitive and don't require reasoning

314 

315### 2025-09-15: Realtime API Beta

316 

317The Realtime API Beta was deprecated and removed from the API on May 12, 2026.

318 

319The interfaces in the Realtime beta API and the released GA API have a few key differences. See [the migration guide](https://developers.openai.com/api/docs/guides/realtime#beta-to-ga-migration) for the current GA interface and related Realtime docs.

320 

321| Shutdown date | Model / system | Recommended replacement |

322| ------------- | ------------------------ | ----------------------- |

323| 2026‑05‑12 | OpenAI-Beta: realtime=v1 | Realtime API |

324 

325### 2025-09-15: `gpt-4o-realtime-preview` models

326 

327In September, 2025, we notified developers using `gpt-4o-realtime-preview` models of their deprecation and removal from the API in six months.

328 

329| Shutdown date | Model / system | Recommended replacement |

330| ------------- | ------------------------------------ | ----------------------- |

331| 2026-05-07 | `gpt-4o-realtime-preview` | `gpt-realtime-1.5` |

332| 2026-05-07 | `gpt-4o-realtime-preview-2025-06-03` | `gpt-realtime-1.5` |

333| 2026-05-07 | `gpt-4o-realtime-preview-2024-12-17` | `gpt-realtime-1.5` |

334| 2026-05-07 | `gpt-4o-mini-realtime-preview` | `gpt-realtime-mini` |

335| 2026-05-07 | `gpt-4o-audio-preview` | `gpt-audio-1.5` |

336| 2026-05-07 | `gpt-4o-mini-audio-preview` | `gpt-audio-mini` |

337 

338### 2025-08-20: Assistants API

339 

340On August 26th, 2025, we notified developers using the Assistants API of its deprecation and removal from the API one year later, on August 26, 2026.

341 

342When we released the [Responses API](https://developers.openai.com/api/reference/resources/responses/methods/create) in [March 2025](https://developers.openai.com/api/docs/changelog), we announced plans to bring all Assistants API features to the easier to use Responses API, with a sunset date in 2026.

343 

344See the Assistants to Conversations [migration guide](https://developers.openai.com/api/docs/assistants/migration) to learn more about how to migrate your current integration to the Responses API and Conversations API.

345 

346| Shutdown date | Model / system | Recommended replacement |

347| ------------- | -------------- | ----------------------------------- |

348| 2026‑08‑26 | Assistants API | Responses API and Conversations API |

349 

350### 2025-06-10: `gpt-4o-realtime-preview-2024-10-01`

351 

352On June 10th, 2025, we notified developers using `gpt-4o-realtime-preview-2024-10-01` of its deprecation and removal from the API in three months.

353 

354| Shutdown date | Model / system | Recommended replacement |

355| ------------- | ------------------------------------ | ----------------------- |

356| 2025-10-10 | `gpt-4o-realtime-preview-2024-10-01` | `gpt-realtime-1.5` |

357 

358### 2025-06-10: `gpt-4o-audio-preview-2024-10-01`

359 

360On June 10th, 2025, we notified developers using `gpt-4o-audio-preview-2024-10-01` of its deprecation and removal from the API in three months.

361 

362| Shutdown date | Model / system | Recommended replacement |

363| ------------- | --------------------------------- | ----------------------- |

364| 2025-10-10 | `gpt-4o-audio-preview-2024-10-01` | `gpt-audio-1.5` |

365 

366### 2025-04-28: `text-moderation`

367 

368On April 28th, 2025, we notified developers using `text-moderation` of its deprecation and removal from the API in six months.

369 

370| Shutdown date | Model / system | Recommended replacement |

371| ------------- | ------------------------ | ----------------------- |

372| 2025-10-27 | `text-moderation-007` | `omni-moderation` |

373| 2025-10-27 | `text-moderation-stable` | `omni-moderation` |

374| 2025-10-27 | `text-moderation-latest` | `omni-moderation` |

375 

376### 2025-04-28: `o1-preview` and `o1-mini`

377 

378On April 28th, 2025, we notified developers using `o1-preview` and `o1-mini` of their deprecations and removal from the API in three months and six months respectively.

379 

380| Shutdown date | Model / system | Recommended replacement |

381| ------------- | -------------- | ----------------------- |

382| 2025-07-28 | `o1-preview` | `o3` |

383| 2025-10-27 | `o1-mini` | `o4-mini` |

384 

385### 2025-04-14: GPT-4.5-preview

386 

387On April 14th, 2025, we notified developers that the `gpt-4.5-preview` model is deprecated and will be removed from the API in the coming months.

388 

389| Shutdown date | Model / system | Recommended replacement |

390| ------------- | ----------------- | ----------------------- |

391| 2025-07-14 | `gpt-4.5-preview` | `gpt-4.1` |

392 

393### 2024-10-02: Assistants API beta v1

394 

395In [April 2024](https://developers.openai.com/api/docs/assistants/migration) when we released the v2 beta version of the Assistants API, we announced that access to the v1 beta would be shut off by the end of 2024. Access to the v1 beta will be discontinued on December 18, 2024.

396 

397See the Assistants API v2 beta [migration guide](https://developers.openai.com/api/docs/assistants/migration) to learn more about how to migrate your tool usage to the latest version of the Assistants API.

398 

399| Shutdown date | Model / system | Recommended replacement |

400| ------------- | -------------------------- | -------------------------- |

401| 2024-12-18 | OpenAI-Beta: assistants=v1 | OpenAI-Beta: assistants=v2 |

402 

403### 2024-08-29: Fine-tuning training on babbage-002 and davinci-002 models

404 

405On August 29th, 2024, we notified developers fine-tuning `babbage-002` and `davinci-002` that new fine-tuning training runs on these models will no longer be supported starting October 28, 2024.

406 

407Fine-tuned models created from these base models are not affected by this deprecation, but you will no longer be able to create new fine-tuned versions with these models.

408 

409| Shutdown date | Model / system | Recommended replacement |

410| ------------- | ----------------------------------------- | ----------------------- |

411| 2024-10-28 | New fine-tuning training on `babbage-002` | `gpt-4o-mini` |

412| 2024-10-28 | New fine-tuning training on `davinci-002` | `gpt-4o-mini` |

413 

414### 2024-06-06: GPT-4-32K and Vision Preview models

415 

416On June 6th, 2024, we notified developers using `gpt-4-32k` and `gpt-4-vision-preview` of their upcoming deprecations in one year and six months respectively. As of June 17, 2024, only existing users of these models will be able to continue using them.

417 

418| Shutdown date | Deprecated model | Deprecated model price | Recommended replacement |

419| ------------- | --------------------------- | -------------------------------------------------- | ----------------------- |

420| 2025-06-06 | `gpt-4-32k` | $60.00 / 1M input tokens + $120 / 1M output tokens | `gpt-4o` |

421| 2025-06-06 | `gpt-4-32k-0613` | $60.00 / 1M input tokens + $120 / 1M output tokens | `gpt-4o` |

422| 2025-06-06 | `gpt-4-32k-0314` | $60.00 / 1M input tokens + $120 / 1M output tokens | `gpt-4o` |

423| 2024-12-06 | `gpt-4-vision-preview` | $10.00 / 1M input tokens + $30 / 1M output tokens | `gpt-4o` |

424| 2024-12-06 | `gpt-4-1106-vision-preview` | $10.00 / 1M input tokens + $30 / 1M output tokens | `gpt-4o` |

425 

426### 2023-11-06: Chat model updates

427 

428On November 6th, 2023, we [announced](https://openai.com/blog/new-models-and-developer-products-announced-at-devday) the release of an updated GPT-3.5 Turbo model (which now comes by default with 16k context) along with deprecation of `gpt-3.5-turbo-0613` and ` gpt-3.5-turbo-16k-0613`. As of June 17, 2024, only existing users of these models will be able to continue using them.

429 

430| Shutdown date | Deprecated model | Deprecated model price | Recommended replacement |

431| ------------- | ------------------------ | -------------------------------------------------- | ----------------------- |

432| 2024-09-13 | `gpt-3.5-turbo-0613` | $1.50 / 1M input tokens + $2.00 / 1M output tokens | `gpt-3.5-turbo` |

433| 2024-09-13 | `gpt-3.5-turbo-16k-0613` | $3.00 / 1M input tokens + $4.00 / 1M output tokens | `gpt-3.5-turbo` |

434 

435Fine-tuned models created from these base models are not affected by this deprecation, but you will no longer be able to create new fine-tuned versions with these models.

436 

437### 2023-08-22: Fine-tunes endpoint

438 

439On August 22nd, 2023, we [announced](https://openai.com/blog/gpt-3-5-turbo-fine-tuning-and-api-updates) the new fine-tuning API (`/v1/fine_tuning/jobs`) and that the original `/v1/fine-tunes` API along with legacy models (including those fine-tuned with the `/v1/fine-tunes` API) will be shut down on January 04, 2024. This means that models fine-tuned using the `/v1/fine-tunes` API will no longer be accessible and you would have to fine-tune new models with the updated endpoint and associated base models.

440 

441#### Fine-tunes endpoint

442 

443| Shutdown date | System | Recommended replacement |

444| ------------- | ---------------- | ----------------------- |

445| 2024-01-04 | `/v1/fine-tunes` | `/v1/fine_tuning/jobs` |

446 

447### 2023-07-06: GPT and embeddings

448 126 

449On July 06, 2023, we [announced](https://openai.com/blog/gpt-4-api-general-availability) the upcoming retirements of older GPT-3 and GPT-3.5 models served via the completions endpoint. We also announced the upcoming retirement of our first-generation text embedding models. They will be shut down on January 04, 2024.

450 127 

451#### InstructGPT models

452 128 

453| Shutdown date | Deprecated model | Deprecated model price | Recommended replacement |

454| ------------- | ------------------ | ---------------------- | ------------------------ |

455| 2024-01-04 | `text-ada-001` | $0.40 / 1M tokens | `gpt-3.5-turbo-instruct` |

456| 2024-01-04 | `text-babbage-001` | $0.50 / 1M tokens | `gpt-3.5-turbo-instruct` |

457| 2024-01-04 | `text-curie-001` | $2.00 / 1M tokens | `gpt-3.5-turbo-instruct` |

458| 2024-01-04 | `text-davinci-001` | $20.00 / 1M tokens | `gpt-3.5-turbo-instruct` |

459| 2024-01-04 | `text-davinci-002` | $20.00 / 1M tokens | `gpt-3.5-turbo-instruct` |

460| 2024-01-04 | `text-davinci-003` | $20.00 / 1M tokens | `gpt-3.5-turbo-instruct` |

461 129 

462Pricing for the replacement `gpt-3.5-turbo-instruct` model can be found on the [pricing page](https://openai.com/api/pricing).

463 130 

464#### Base GPT models

465 131 

466| Shutdown date | Deprecated model | Deprecated model price | Recommended replacement |132| Shutdown date | Affected model or feature | Listed replacement | Notice date |

467| ------------- | ------------------ | ---------------------- | ------------------------ |133| -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------ |

468| 2024-01-04 | `ada` | $0.40 / 1M tokens | `babbage-002` |134| **Oct 23, 2026** | `gpt-3.5-turbo-0125`, `gpt-3.5-turbo`, `gpt-3.5-turbo-completions` | `gpt-5.6-terra` | Apr 22, 2026 |

469| 2024-01-04 | `babbage` | $0.50 / 1M tokens | `babbage-002` |135| **Oct 23, 2026** | `gpt-4-0613`, `gpt-4`, `gpt-4-0613-completions`, `gpt-4-completions` | `gpt-5.6-sol` | Apr 22, 2026 |

470| 2024-01-04 | `curie` | $2.00 / 1M tokens | `davinci-002` |136| **Oct 23, 2026** | `gpt-4-1106-preview` | `gpt-5.6-sol` | Apr 22, 2026 |

471| 2024-01-04 | `davinci` | $20.00 / 1M tokens | `davinci-002` |137| **Oct 23, 2026** | `gpt-4-turbo`, `gpt-4-turbo-2024-04-09`, `gpt-4-turbo-completions` | `gpt-5.6-sol` | Apr 22, 2026 |

472| 2024-01-04 | `code-davinci-002` | --- | `gpt-3.5-turbo-instruct` |138| **Oct 23, 2026** | `gpt-4.1-nano`, `gpt-4.1-nano-2025-04-14` | `gpt-5.6-luna` | Apr 22, 2026 |

473 139| **Oct 23, 2026** | `gpt-4o-2024-05-13` | `gpt-5.6-sol` | Apr 22, 2026 |

474Pricing for the replacement `babbage-002` and `davinci-002` models can be found on the [pricing page](https://openai.com/api/pricing).140| **Oct 23, 2026** | `gpt-image-1` | `gpt-image-2.5-sunburst` or `gpt-image-2.5-flare` | Apr 22, 2026 |

475 141| **Oct 23, 2026** | `o1-2024-12-17`, `o1` | `gpt-5.6-sol` | Apr 22, 2026 |

476#### Edit models & endpoint142| **Oct 23, 2026** | `o1-pro-2025-03-19`, `o1-pro` | `gpt-5.6-sol` (`reasoning.mode: pro`) | Apr 22, 2026 |

477 143| **Oct 23, 2026** | `o3-mini-2025-01-31`, `o3-mini` | `gpt-5.6-sol` | Apr 22, 2026 |

478| Shutdown date | Model / system | Recommended replacement |144| **Oct 23, 2026** | `ft-o4-mini-2025-04-16` | `gpt-5.6-terra` | Apr 22, 2026 |

479| ------------- | ----------------------- | ----------------------- |145| **Oct 23, 2026** | `o4-mini-2025-04-16`, `o4-mini` | `gpt-5.6-terra` | Apr 22, 2026 |

480| 2024-01-04 | `text-davinci-edit-001` | `gpt-4o` |146| **Oct 1, 2026** | `gpt-5.4-cyber` | The most capable cyber model available to you. | Sep 11, 2026 |

481| 2024-01-04 | `code-davinci-edit-001` | `gpt-4o` |147| **Sep 28, 2026** | `gpt-3.5-turbo-instruct` | `gpt-5.6-terra` | Sep 26, 2025 |

482| 2024-01-04 | `/v1/edits` | `/v1/chat/completions` |148| **Sep 28, 2026** | `babbage-002` | `gpt-5.6-terra` | Sep 26, 2025 |

483 149| **Sep 28, 2026** | `davinci-002` | `gpt-5.6-terra` | Sep 26, 2025 |

484#### Fine-tuning GPT models150| **Sep 28, 2026** | `gpt-3.5-turbo-1106` | `gpt-5.6-terra` | Sep 26, 2025 |

485 151| **Sep 24, 2026** | Videos API | No one-to-one replacement | Mar 24, 2026 |

486| Shutdown date | Deprecated model | Training price | Usage price | Recommended replacement |152| **Sep 24, 2026** | `sora-2` | No one-to-one replacement | Mar 24, 2026 |

487| ------------- | ---------------- | ------------------ | ------------------- | ---------------------------------------- |153| **Sep 24, 2026** | `sora-2-pro` | No one-to-one replacement | Mar 24, 2026 |

488| 2024-01-04 | `ada` | $0.40 / 1M tokens | $1.60 / 1M tokens | `babbage-002` |154| **Sep 24, 2026** | `sora-2-2025-10-06` | No one-to-one replacement | Mar 24, 2026 |

489| 2024-01-04 | `babbage` | $0.60 / 1M tokens | $2.40 / 1M tokens | `babbage-002` |155| **Sep 24, 2026** | `sora-2-2025-12-08` | No one-to-one replacement | Mar 24, 2026 |

490| 2024-01-04 | `curie` | $3.00 / 1M tokens | $12.00 / 1M tokens | `davinci-002` |156| **Sep 24, 2026** | `sora-2-pro-2025-10-06` | No one-to-one replacement | Mar 24, 2026 |

491| 2024-01-04 | `davinci` | $30.00 / 1M tokens | $120.00 / 1K tokens | `davinci-002`, `gpt-3.5-turbo`, `gpt-4o` |157| **Aug 26, 2026** | Assistants API | Responses API and Conversations API ([migration guide](https://developers.openai.com/api/docs/assistants/migration)) | Aug 26, 2025 |

492 158| **Aug 10, 2026** | `gpt-5.2-chat-latest` | `gpt-5.6-sol` | May 8, 2026 |

493#### First-generation text embedding models159| **Aug 10, 2026** | `gpt-5.3-chat-latest` | `gpt-5.6-sol` | May 8, 2026 |

494 160| **Jul 23, 2026** | `computer-use-preview-2025-03-11`, `computer-use-preview` | `gpt-5.6-terra` | Apr 22, 2026 |

495| Shutdown date | Deprecated model | Deprecated model price | Recommended replacement |161| **Jul 23, 2026** | `gpt-4o-mini-search-preview-2025-03-11` | `gpt-5.6-terra` | Apr 22, 2026 |

496| ------------- | ------------------------------- | ---------------------- | ------------------------ |162| **Jul 23, 2026** | `gpt-4o-search-preview-2025-03-11` | `gpt-5.6-terra` | Apr 22, 2026 |

497| 2024-01-04 | `text-similarity-ada-001` | $4.00 / 1M tokens | `text-embedding-3-small` |163| **Jul 23, 2026** | `gpt-5-chat-latest` | `gpt-5.6-sol` | Apr 22, 2026 |

498| 2024-01-04 | `text-search-ada-doc-001` | $4.00 / 1M tokens | `text-embedding-3-small` |164| **Jul 23, 2026** | `gpt-5-codex` | `gpt-5.6-sol` | Apr 22, 2026 |

499| 2024-01-04 | `text-search-ada-query-001` | $4.00 / 1M tokens | `text-embedding-3-small` |165| **Jul 23, 2026** | `gpt-5.1-chat-latest` | `gpt-5.6-sol` | Apr 22, 2026 |

500| 2024-01-04 | `code-search-ada-code-001` | $4.00 / 1M tokens | `text-embedding-3-small` |166| **Jul 23, 2026** | `gpt-5.1-codex` | `gpt-5.6-sol` | Apr 22, 2026 |

501| 2024-01-04 | `code-search-ada-text-001` | $4.00 / 1M tokens | `text-embedding-3-small` |167| **Jul 23, 2026** | `gpt-5.1-codex-max` | `gpt-5.6-sol` | Apr 22, 2026 |

502| 2024-01-04 | `text-similarity-babbage-001` | $5.00 / 1M tokens | `text-embedding-3-small` |168| **Jul 23, 2026** | `gpt-5.1-codex-mini` | `gpt-5.6-terra` | Apr 22, 2026 |

503| 2024-01-04 | `text-search-babbage-doc-001` | $5.00 / 1M tokens | `text-embedding-3-small` |169| **Jul 23, 2026** | `gpt-audio-mini-2025-10-06` | `gpt-audio-1.5` | Apr 22, 2026 |

504| 2024-01-04 | `text-search-babbage-query-001` | $5.00 / 1M tokens | `text-embedding-3-small` |170| **Jul 23, 2026** | `gpt-realtime-mini-2025-10-06` | `gpt-realtime-2.1-mini` | Apr 22, 2026 |

505| 2024-01-04 | `code-search-babbage-code-001` | $5.00 / 1M tokens | `text-embedding-3-small` |171| **Jul 23, 2026** | `o3-deep-research-2025-06-26`, `o3-deep-research` | `gpt-5.6-sol` | Apr 22, 2026 |

506| 2024-01-04 | `code-search-babbage-text-001` | $5.00 / 1M tokens | `text-embedding-3-small` |172| **Jul 23, 2026** | `o4-mini-deep-research-2025-06-26`, `o4-mini-deep-research` | `gpt-5.6-sol` | Apr 22, 2026 |

507| 2024-01-04 | `text-similarity-curie-001` | $20.00 / 1M tokens | `text-embedding-3-small` |173| **Jul 23, 2026** | `gpt-5.2-codex` | `gpt-5.6-sol` | Apr 22, 2026 |

508| 2024-01-04 | `text-search-curie-doc-001` | $20.00 / 1M tokens | `text-embedding-3-small` |174| **May 12, 2026** | `dall-e-2` | `gpt-image-2`, `gpt-image-1`, or `gpt-image-1-mini` | Nov 14, 2025 |

509| 2024-01-04 | `text-search-curie-query-001` | $20.00 / 1M tokens | `text-embedding-3-small` |175| **May 12, 2026** | `dall-e-3` | `gpt-image-2`, `gpt-image-1`, or `gpt-image-1-mini` | Nov 14, 2025 |

510| 2024-01-04 | `text-similarity-davinci-001` | $200.00 / 1M tokens | `text-embedding-3-small` |176| **May 12, 2026** | OpenAI-Beta: realtime=v1 | [Realtime API migration guide](https://developers.openai.com/api/docs/guides/realtime#beta-to-ga-migration) | Sep 15, 2025 |

511| 2024-01-04 | `text-search-davinci-doc-001` | $200.00 / 1M tokens | `text-embedding-3-small` |177| **May 7, 2026** | `gpt-4o-realtime-preview` | `gpt-realtime-1.5` | Sep 15, 2025 |

512| 2024-01-04 | `text-search-davinci-query-001` | $200.00 / 1M tokens | `text-embedding-3-small` |178| **May 7, 2026** | `gpt-4o-realtime-preview-2025-06-03` | `gpt-realtime-1.5` | Sep 15, 2025 |

513 179| **May 7, 2026** | `gpt-4o-realtime-preview-2024-12-17` | `gpt-realtime-1.5` | Sep 15, 2025 |

514### 2023-06-13: Updated chat models180| **May 7, 2026** | `gpt-4o-mini-realtime-preview` | `gpt-realtime-mini` | Sep 15, 2025 |

515 181| **May 7, 2026** | `gpt-4o-audio-preview` | `gpt-audio-1.5` | Sep 15, 2025 |

516On June 13, 2023, we announced new chat model versions in the [Function calling and other API updates](https://openai.com/blog/function-calling-and-other-api-updates) blog post. The three original versions will be retired in June 2024 at the earliest. As of January 10, 2024, only existing users of these models will be able to continue using them.182| **May 7, 2026** | `gpt-4o-mini-audio-preview` | `gpt-audio-mini` | Sep 15, 2025 |

517 183| **Mar 26, 2026** | `gpt-4-0314` | `gpt-5`, or `gpt-4.1` for latency-sensitive tasks that don't require reasoning | Sep 26, 2025 |

518| Shutdown date | Legacy model | Legacy model price | Recommended replacement |184| **Mar 26, 2026** | `gpt-4-0125-preview` (including `gpt-4-turbo-preview` and `gpt-4-turbo-preview-completions`, which point to this snapshot) | `gpt-5`, or `gpt-4.1` for latency-sensitive tasks that don't require reasoning | Sep 26, 2025 |

519| ---------------------- | ------------ | ---------------------------------------------------- | ----------------------- |185| **Feb 17, 2026** | `chatgpt-4o-latest` | `gpt-5.1-chat-latest` | Nov 18, 2025 |

520| at earliest 2024-06-13 | `gpt-4-0314` | $30.00 / 1M input tokens + $60.00 / 1M output tokens | `gpt-4o` |186| **Feb 12, 2026** | `codex-mini-latest` | `gpt-5-codex-mini` | Nov 17, 2025 |

521 187| **Oct 27, 2025** | `text-moderation-007` | `omni-moderation` | Apr 28, 2025 |

522| Shutdown date | Deprecated model | Deprecated model price | Recommended replacement |188| **Oct 27, 2025** | `text-moderation-stable` | `omni-moderation` | Apr 28, 2025 |

523| ------------- | -------------------- | ----------------------------------------------------- | ----------------------- |189| **Oct 27, 2025** | `text-moderation-latest` | `omni-moderation` | Apr 28, 2025 |

524| 2024-09-13 | `gpt-3.5-turbo-0301` | $15.00 / 1M input tokens + $20.00 / 1M output tokens | `gpt-3.5-turbo` |190| **Oct 27, 2025** | `o1-mini` | `o4-mini` | Apr 28, 2025 |

525| 2025-06-06 | `gpt-4-32k-0314` | $60.00 / 1M input tokens + $120.00 / 1M output tokens | `gpt-4o` |191| **Oct 10, 2025** | `gpt-4o-realtime-preview-2024-10-01` | `gpt-realtime-1.5` | Jun 10, 2025 |

526 192| **Oct 10, 2025** | `gpt-4o-audio-preview-2024-10-01` | `gpt-audio-1.5` | Jun 10, 2025 |

527### 2023-03-20: Codex models193| **Jul 28, 2025** | `o1-preview` | `o3` | Apr 28, 2025 |

528 194| **Jul 14, 2025** | `gpt-4.5-preview` | `gpt-4.1` | Apr 14, 2025 |

529| Shutdown date | Deprecated model | Recommended replacement |195| **Jun 6, 2025** | `gpt-4-32k` Historical price $60.00 / 1M input tokens + $120 / 1M output tokens | `gpt-4o` | Jun 6, 2024 |

530| ------------- | ------------------ | ----------------------- |196| **Jun 6, 2025** | `gpt-4-32k-0613` Historical price $60.00 / 1M input tokens + $120 / 1M output tokens | `gpt-4o` | Jun 6, 2024 |

531| 2023-03-23 | `code-davinci-002` | `gpt-4o` |197| **Jun 6, 2025** | `gpt-4-32k-0314` Historical price $60.00 / 1M input tokens + $120 / 1M output tokens | `gpt-4o` | Jun 13, 2023 |

532| 2023-03-23 | `code-davinci-001` | `gpt-4o` |198| **Dec 18, 2024** | OpenAI-Beta: assistants=v1 | OpenAI-Beta: assistants=v2 ([migration guide](https://developers.openai.com/api/docs/assistants/migration)) | Oct 2, 2024 |

533| 2023-03-23 | `code-cushman-002` | `gpt-4o` |199| **Dec 6, 2024** | `gpt-4-vision-preview` Historical price $10.00 / 1M input tokens + $30 / 1M output tokens | `gpt-4o` | Jun 6, 2024 |

534| 2023-03-23 | `code-cushman-001` | `gpt-4o` |200| **Dec 6, 2024** | `gpt-4-1106-vision-preview` Historical price $10.00 / 1M input tokens + $30 / 1M output tokens | `gpt-4o` | Jun 6, 2024 |

535 201| **Oct 28, 2024** | New fine-tuning training on `babbage-002` | `gpt-4o-mini` | Aug 29, 2024 |

536### 2022-06-03: Legacy endpoints202| **Oct 28, 2024** | New fine-tuning training on `davinci-002` | `gpt-4o-mini` | Aug 29, 2024 |

537 203| **Sep 13, 2024** | `gpt-3.5-turbo-0613` Historical price $1.50 / 1M input tokens + $2.00 / 1M output tokens | `gpt-3.5-turbo` | Nov 6, 2023 |

538| Shutdown date | System | Recommended replacement |204| **Sep 13, 2024** | `gpt-3.5-turbo-16k-0613` Historical price $3.00 / 1M input tokens + $4.00 / 1M output tokens | `gpt-3.5-turbo` | Nov 6, 2023 |

539| ------------- | --------------------- | ----------------------------------------------------------------------------------------------------- |205| **Sep 13, 2024** | `gpt-3.5-turbo-0301` Historical price $15.00 / 1M input tokens + $20.00 / 1M output tokens | `gpt-3.5-turbo` | Jun 13, 2023 |

540| 2022-12-03 | `/v1/engines` | [/v1/models](https://platform.openai.com/docs/api-reference/models/list) |206| **Jun 13, 2024** Earliest estimate | `gpt-4-0314` Historical price $30.00 / 1M input tokens + $60.00 / 1M output tokens | `gpt-4o` | Jun 13, 2023 |

541| 2022-12-03 | `/v1/search` | [View transition guide](https://help.openai.com/en/articles/6272952-search-transition-guide) |207| **Jan 4, 2024** | `/v1/fine-tunes` | `/v1/fine_tuning/jobs` | Aug 22, 2023 |

542| 2022-12-03 | `/v1/classifications` | [View transition guide](https://help.openai.com/en/articles/6272941-classifications-transition-guide) |208| **Jan 4, 2024** | `text-ada-001` Historical price $0.40 / 1M tokens | `gpt-3.5-turbo-instruct` | Jul 6, 2023 |

543| 2022-12-03 | `/v1/answers` | [View transition guide](https://help.openai.com/en/articles/6233728-answers-transition-guide) |209| **Jan 4, 2024** | `text-babbage-001` Historical price $0.50 / 1M tokens | `gpt-3.5-turbo-instruct` | Jul 6, 2023 |

544 210| **Jan 4, 2024** | `text-curie-001` Historical price $2.00 / 1M tokens | `gpt-3.5-turbo-instruct` | Jul 6, 2023 |

545### Plain-text aliases211| **Jan 4, 2024** | `text-davinci-001` Historical price $20.00 / 1M tokens | `gpt-3.5-turbo-instruct` | Jul 6, 2023 |

546 212| **Jan 4, 2024** | `text-davinci-002` Historical price $20.00 / 1M tokens | `gpt-3.5-turbo-instruct` | Jul 6, 2023 |

547- gpt-image-2 | gpt-image-2-2026-04-21213| **Jan 4, 2024** | `text-davinci-003` Historical price $20.00 / 1M tokens | `gpt-3.5-turbo-instruct` | Jul 6, 2023 |

548- gpt-5.4-nano | gpt-5.4-nano-2026-03-17214| **Jan 4, 2024** | `ada` Historical price $0.40 / 1M tokens | `babbage-002` | Jul 6, 2023 |

549- gpt-5.1 | gpt-5.1-2025-11-13215| **Jan 4, 2024** | `babbage` Historical price $0.50 / 1M tokens | `babbage-002` | Jul 6, 2023 |

550- gpt-4o-mini-tts | gpt-4o-mini-tts-2025-03-20216| **Jan 4, 2024** | `curie` Historical price $2.00 / 1M tokens | `davinci-002` | Jul 6, 2023 |

551- gpt-4o-mini-tts | gpt-4o-mini-tts-2025-12-15217| **Jan 4, 2024** | `davinci` Historical price $20.00 / 1M tokens | `davinci-002` | Jul 6, 2023 |

552- gpt-4o-mini-transcribe | gpt-4o-mini-transcribe-2025-12-15218| **Jan 4, 2024** | `code-davinci-002` (base GPT models) | `gpt-3.5-turbo-instruct` | Jul 6, 2023 |

553- gpt-realtime | gpt-realtime-2025-08-28219| **Jan 4, 2024** | `text-davinci-edit-001` | `gpt-4o` | Jul 6, 2023 |

554- gpt-audio | gpt-audio-2025-08-28220| **Jan 4, 2024** | `code-davinci-edit-001` | `gpt-4o` | Jul 6, 2023 |

555- gpt-realtime-mini | gpt-realtime-mini-2025-12-15221| **Jan 4, 2024** | `/v1/edits` | `/v1/chat/completions` | Jul 6, 2023 |

556- gpt-audio-mini | gpt-audio-mini-2025-12-15222| **Jan 4, 2024** | Fine-tuning on `ada` Training price $0.40 / 1M tokens. Usage price $1.60 / 1M tokens | `babbage-002` | Jul 6, 2023 |

557- gpt-5 | gpt-5-2025-08-07223| **Jan 4, 2024** | Fine-tuning on `babbage` Training price $0.60 / 1M tokens. Usage price $2.40 / 1M tokens | `babbage-002` | Jul 6, 2023 |

558- gpt-5-mini | gpt-5-mini-2025-08-07224| **Jan 4, 2024** | Fine-tuning on `curie` Training price $3.00 / 1M tokens. Usage price $12.00 / 1M tokens | `davinci-002` | Jul 6, 2023 |

559- gpt-5-nano | gpt-5-nano-2025-08-07225| **Jan 4, 2024** | Fine-tuning on `davinci` Training price $30.00 / 1M tokens. Usage price $120.00 / 1K tokens | `davinci-002`, `gpt-3.5-turbo`, `gpt-4o` | Jul 6, 2023 |

560- gpt-5-pro | gpt-5-pro-2025-10-06226| **Jan 4, 2024** | `text-similarity-ada-001` Historical price $4.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

561- o3 | o3-2025-04-16227| **Jan 4, 2024** | `text-search-ada-doc-001` Historical price $4.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

562- o3-pro | o3-pro-2025-06-10228| **Jan 4, 2024** | `text-search-ada-query-001` Historical price $4.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

563- gpt-image-1.5 | gpt-image-1.5-2025-12-16229| **Jan 4, 2024** | `code-search-ada-code-001` Historical price $4.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

564- gpt-3.5-turbo-0125 | gpt-3.5-turbo, gpt-3.5-turbo-completions230| **Jan 4, 2024** | `code-search-ada-text-001` Historical price $4.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

565- gpt-4-0613 | gpt-4, gpt-4-0613-completions, gpt-4-completions231| **Jan 4, 2024** | `text-similarity-babbage-001` Historical price $5.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

566- gpt-4-turbo | gpt-4-turbo-2024-04-09, gpt-4-turbo-completions232| **Jan 4, 2024** | `text-search-babbage-doc-001` Historical price $5.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

567- gpt-4.1-nano | gpt-4.1-nano-2025-04-14233| **Jan 4, 2024** | `text-search-babbage-query-001` Historical price $5.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

568- o1-2024-12-17 | o1234| **Jan 4, 2024** | `code-search-babbage-code-001` Historical price $5.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

569- o1-pro-2025-03-19 | o1-pro235| **Jan 4, 2024** | `code-search-babbage-text-001` Historical price $5.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

570- o3-mini-2025-01-31 | o3-mini236| **Jan 4, 2024** | `text-similarity-curie-001` Historical price $20.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

571- o4-mini-2025-04-16 | o4-mini237| **Jan 4, 2024** | `text-search-curie-doc-001` Historical price $20.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

572- computer-use-preview-2025-03-11 | computer-use-preview238| **Jan 4, 2024** | `text-search-curie-query-001` Historical price $20.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

573- o3-deep-research-2025-06-26 | o3-deep-research239| **Jan 4, 2024** | `text-similarity-davinci-001` Historical price $200.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

574- o4-mini-deep-research-2025-06-26 | o4-mini-deep-research240| **Jan 4, 2024** | `text-search-davinci-doc-001` Historical price $200.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

241| **Jan 4, 2024** | `text-search-davinci-query-001` Historical price $200.00 / 1M tokens | `text-embedding-3-small` | Jul 6, 2023 |

242| **Mar 23, 2023** | `code-davinci-002` (Codex models) | `gpt-4o` | Mar 20, 2023 |

243| **Mar 23, 2023** | `code-davinci-001` | `gpt-4o` | Mar 20, 2023 |

244| **Mar 23, 2023** | `code-cushman-002` | `gpt-4o` | Mar 20, 2023 |

245| **Mar 23, 2023** | `code-cushman-001` | `gpt-4o` | Mar 20, 2023 |

246| **Dec 3, 2022** | `/v1/engines` | [/v1/models](https://platform.openai.com/docs/api-reference/models/list) | Jun 3, 2022 |

247| **Dec 3, 2022** | `/v1/search` | [View transition guide](https://help.openai.com/en/articles/6272952-search-transition-guide) | Jun 3, 2022 |

248| **Dec 3, 2022** | `/v1/classifications` | [View transition guide](https://help.openai.com/en/articles/6272941-classifications-transition-guide) | Jun 3, 2022 |

249| **Dec 3, 2022** | `/v1/answers` | [View transition guide](https://help.openai.com/en/articles/6233728-answers-transition-guide) | Jun 3, 2022 |

250 

251 

252 

253 

254### Historical notes

255 

256- Fine-tuned versions of the [legacy GPT models shut down in October 2026](https://developers.openai.com/api/docs/deprecations#2026-04-22-legacy-gpt-model-snapshots) followed the same shutdown schedule as their underlying base models.

257- The [`codex-mini-latest` shutdown](https://developers.openai.com/api/docs/deprecations#2025-11-17-codex-mini-latest-model-snapshot) also ended support for the legacy local shell tool. For new integrations, use the [shell tool](https://developers.openai.com/api/docs/guides/tools-shell).

258- The [Assistants API notice](https://developers.openai.com/api/docs/deprecations#2025-08-20-assistants-api) followed the release of the Responses API in [March 2025](https://developers.openai.com/api/docs/changelog). We first announced plans to retire the Assistants API v1 beta when we [released v2 in April 2024](https://developers.openai.com/api/docs/assistants/migration).

259- The October 2024 shutdown for [fine-tuning training on `babbage-002` and `davinci-002`](https://developers.openai.com/api/docs/deprecations#2024-08-29-fine-tuning-training-on-babbage-002-and-davinci-002-models) applied to creating new fine-tuned models. Existing fine-tuned models were unaffected by that change.

260- The June 6, 2024 notice reconfirmed the retirement of `gpt-4-32k-0314`. Starting June 17, 2024, access to the GPT-4-32K and Vision Preview models and the GPT-3.5 Turbo snapshots announced in [November 2023](https://openai.com/blog/new-models-and-developer-products-announced-at-devday) was limited to existing users. Existing fine-tuned models from those GPT-3.5 Turbo snapshots were unaffected by that shutdown.

261- The [legacy fine-tunes endpoint shutdown](https://developers.openai.com/api/docs/deprecations#2023-08-22-fine-tunes-endpoint) also removed access to models trained with that endpoint. Developers had to train new models through the [updated fine-tuning API](https://openai.com/blog/gpt-3-5-turbo-fine-tuning-and-api-updates).

262- The [July 2023 announcement](https://openai.com/blog/gpt-4-api-general-availability) covered older GPT-3 and GPT-3.5 models served through the completions endpoint and first-generation text embedding models. See the [pricing page](https://openai.com/api/pricing) for current model pricing.

263- The [June 2023 announcement](https://openai.com/blog/function-calling-and-other-api-updates) gave an earliest retirement date of June 13, 2024 for the original chat models. Starting January 10, 2024, access was limited to existing users. See the [March 2026 shutdown notice](https://developers.openai.com/api/docs/deprecations#2025-09-26-legacy-gpt-model-snapshots-march-2026-shutdown) for the final shutdown date of `gpt-4-0314`.

Details

24 24 

25Set up the SDK with an Admin API key25Set up the SDK with an Admin API key

26 26 

27```javascript27```typescript

28import OpenAI from "openai";28import OpenAI from "openai";

29 29 

30const client = new OpenAI({30const client = new OpenAI({


80 80 

81Set a project model allowlist/denylist81Set a project model allowlist/denylist

82 82 

83```javascript83```typescript

84const modelPermissions =84const modelPermissions =

85 await client.admin.organization.projects.modelPermissions.update("proj_abc", {85 await client.admin.organization.projects.modelPermissions.update("proj_abc", {

86 mode: "allow_list",86 mode: "allow_list",


173 173 

174Create a project spend limit alert174Create a project spend limit alert

175 175 

176```javascript176```typescript

177const spendAlert = await client.admin.organization.projects.spendAlerts.create(177const spendAlert = await client.admin.organization.projects.spendAlerts.create(

178 "proj_abc",178 "proj_abc",

179 {179 {


280 280 

281Set project data retention281Set project data retention

282 282 

283```javascript283```typescript

284const dataRetention =284const dataRetention =

285 await client.admin.organization.projects.dataRetention.update("proj_abc", {285 await client.admin.organization.projects.dataRetention.update("proj_abc", {

286 retention_type: "organization_default",286 retention_type: "organization_default",


350 350 

351Invite a user by email351Invite a user by email

352 352 

353```javascript353```typescript

354const invite = await client.admin.organization.invites.create({354const invite = await client.admin.organization.invites.create({

355 email: "user@example.com",355 email: "user@example.com",

356 role: "reader",356 role: "reader",


416 416 

417Retrieve audit logs417Retrieve audit logs

418 418 

419```javascript419```typescript

420const auditLogs = await client.admin.organization.auditLogs.list({420const auditLogs = await client.admin.organization.auditLogs.list({

421 limit: 10,421 limit: 10,

422});422});

Details

120 120 

121The following historical example shows how to read the API's prompt token count. It cannot run against the retired model:121The following historical example shows how to read the API's prompt token count. It cannot run against the retired model:

122 122 

123```javascript123```typescript

124import OpenAI from "openai";124import OpenAI from "openai";

125 125 

126const client = new OpenAI();126const client = new OpenAI();


131 temperature: 0,131 temperature: 0,

132});132});

133 133 

134if (!response.usage)

135 throw new Error("The response did not include token usage.");

134console.log(`${response.usage.prompt_tokens} prompt tokens used.`);136console.log(`${response.usage.prompt_tokens} prompt tokens used.`);

135```137```

136 138 

Details

17 17 

18Configure an agent for one session18Configure an agent for one session

19 19 

20```javascript20```typescript

21import OpenAI from "openai";21import OpenAI from "openai";

22const client = new OpenAI();22const client = new OpenAI();

23 23 


165 165 

166Reuse an agent166Reuse an agent

167 167 

168```javascript168```typescript

169import OpenAI from "openai";169import OpenAI from "openai";

170 170 

171const client = new OpenAI();171const client = new OpenAI();


308 308 

309Override an agent for one session309Override an agent for one session

310 310 

311```javascript311```typescript

312// Replace the illustrative IDs and URLs below with your own resource values.312// Replace the illustrative IDs and URLs below with your own resource values.

313import OpenAI from "openai";313import OpenAI from "openai";

314const client = new OpenAI();314const client = new OpenAI();

Details

151 151 

152Create summary.json152Create summary.json

153 153 

154```javascript154```typescript

155import OpenAI from "openai";155import OpenAI from "openai";

156import { agentFileDestination } from "openai/helpers/beta/agents/filesystem";156import { agentFileDestination } from "openai/helpers/beta/agents/filesystem";

157 157 

Details

34 34 

35Send the workspace configuration to `POST /v1/agents/environments`:35Send the workspace configuration to `POST /v1/agents/environments`:

36 36 

37```javascript37```typescript

38import OpenAI from "openai";38import OpenAI from "openai";

39 39 

40const client = new OpenAI();40const client = new OpenAI();


170 170 

171Retrieve the environment using the ID saved in step 1:171Retrieve the environment using the ID saved in step 1:

172 172 

173```javascript173```typescript

174const current = await client.beta.agents.environments.retrieve(environmentId);174const current = await client.beta.agents.environments.retrieve(environmentId);

175console.log(current.status);175console.log(current.status);

176```176```


218 218 

219Create a session with the saved environment ID, an agent, and its first input:219Create a session with the saved environment ID, an agent, and its first input:

220 220 

221```javascript221```typescript

222const stream = await client.beta.agents.sessions.create({222const stream = await client.beta.agents.sessions.create({

223 agent: { model: "gpt-6-astra" },223 agent: { model: "gpt-6-astra" },

224 environment: { type: "openai_hosted", environment_id: environmentId },224 environment: { type: "openai_hosted", environment_id: environmentId },


302 302 

303If multiple tasks need the same packages and setup, [save an environment configuration as a template](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/environments/subresources/templates/methods/create), then supply its ID when creating each pre-warmed environment:303If multiple tasks need the same packages and setup, [save an environment configuration as a template](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/environments/subresources/templates/methods/create), then supply its ID when creating each pre-warmed environment:

304 304 

305```javascript305```typescript

306import OpenAI from "openai";306import OpenAI from "openai";

307 307 

308const client = new OpenAI();308const client = new OpenAI();


370 370 

371For browser tasks, prepare the managed browser and virtual display before the session starts. Include `desktop.enabled` when creating the environment:371For browser tasks, prepare the managed browser and virtual display before the session starts. Include `desktop.enabled` when creating the environment:

372 372 

373```javascript373```typescript

374import OpenAI from "openai";374import OpenAI from "openai";

375 375 

376const client = new OpenAI();376const client = new OpenAI();


443 443 

444Use `GET /v1/agents/environments` to find active environments created by your identity in the current organization and project:444Use `GET /v1/agents/environments` to find active environments created by your identity in the current organization and project:

445 445 

446```javascript446```typescript

447const environments = await client.beta.agents.environments.list({447const environments = await client.beta.agents.environments.list({

448 limit: 20,448 limit: 20,

449 order: "desc",449 order: "desc",


495- **Multiple sessions can share one environment.** Pass the same `environment_id` when creating each session. They share the running workspace, including files, processes, installed packages, and environment configuration. Each session keeps its own conversation history. Changes to the workspace are visible to other attached sessions, so create separate environments when tasks need separate workspaces. A shared environment supports up to 128 attached sessions. This behavior applies to newly created standalone environments; older environments retain their original lifecycle.495- **Multiple sessions can share one environment.** Pass the same `environment_id` when creating each session. They share the running workspace, including files, processes, installed packages, and environment configuration. Each session keeps its own conversation history. Changes to the workspace are visible to other attached sessions, so create separate environments when tasks need separate workspaces. A shared environment supports up to 128 attached sessions. This behavior applies to newly created standalone environments; older environments retain their original lifecycle.

496- **Unused environments expire.** An environment that remains unattached expires after 5 minutes. Prewarm close to when you expect a task to start.496- **Unused environments expire.** An environment that remains unattached expires after 5 minutes. Prewarm close to when you expect a task to start.

497- **Keep the creating identity consistent.** Retrieval, listing, and attachment require the same organization, project, and authenticated identity that created the environment. Different API keys for that identity can access the same environments, including after key rotation.497- **Keep the creating identity consistent.** Retrieval, listing, and attachment require the same organization, project, and authenticated identity that created the environment. Different API keys for that identity can access the same environments, including after key rotation.

498- **Shared environments expire after inactivity.** The first attachment starts a 20-minute idle lifetime. Activity in any attached session or through the environment file API extends it; pending work and active turns prevent idle expiry. Deleting a session removes that session from the environment without deleting the shared workspace. Even after the last session is deleted, the environment remains available for attachment until its idle deadline. The API has no standalone environment deletion endpoint.498- **Shared compute stops after inactivity.** The first attachment starts a 20-minute idle lifetime. Activity in any attached session or through the environment file API extends it; pending work and active turns prevent idle shutdown. At idle shutdown, an environment can enter `suspended` with a checkpoint retained for 7 days instead of expiring. Suspension stops compute; it does not delete the shared workspace. Deleting a session removes that session from the environment without deleting the shared workspace or its checkpoint. The API has no standalone environment deletion endpoint.

499 499 

500## Retry creation safely500## Retry creation safely

501 501 

Details

61 61 

62Check Worker health62Check Worker health

63 63 

64```javascript64```typescript

65// Replace the illustrative IDs and URLs below with your own resource values.65// Replace the illustrative IDs and URLs below with your own resource values.

66 66 

67const response = await fetch(67const response = await fetch(


169 169 

170Clean up the Worker sandbox170Clean up the Worker sandbox

171 171 

172```javascript172```typescript

173// Replace the illustrative IDs and URLs below with your own resource values.173// Replace the illustrative IDs and URLs below with your own resource values.

174 174 

175const response = await fetch("https://worker.example.com/executors/sess_123", {175const response = await fetch("https://worker.example.com/executors/sess_123", {

Details

73 73 

74Create a session with your own environment74Create a session with your own environment

75 75 

76```javascript76```typescript

77import OpenAI from "openai";77import OpenAI from "openai";

78const client = new OpenAI();78const client = new OpenAI();

79 79 

Details

24 24 

25Compare release notes25Compare release notes

26 26 

27```javascript27```typescript

28import OpenAI from "openai";28import OpenAI from "openai";

29 29 

30const client = new OpenAI();30const client = new OpenAI();


207 207 

208Enable delegation with your own environment208Enable delegation with your own environment

209 209 

210```javascript210```typescript

211const result = await client.beta.agents.sessions.create({211const result = await client.beta.agents.sessions.create({

212 agent: {212 agent: {

213 model: "gpt-6-astra",213 model: "gpt-6-astra",


355 355 

356Identify the agent that ran a command356Identify the agent that ran a command

357 357 

358```javascript358```typescript

359// Use the saved session ID and command execution item from your application.359// Use the saved session ID and command execution item from your application.

360const turn = await client.beta.agents.sessions.turns.retrieve(360const turn = await client.beta.agents.sessions.turns.retrieve(

361 command.turn_id,361 command.turn_id,

Details

23 23 

24Follow live session events24Follow live session events

25 25 

26```javascript26```typescript

27// Replace the illustrative IDs and URLs below with your own resource values.27// Replace the illustrative IDs and URLs below with your own resource values.

28import OpenAI from "openai";28import OpenAI from "openai";

29 29 


171 171 

172Inspect saved session items172Inspect saved session items

173 173 

174```javascript174```typescript

175// Replace the illustrative IDs and URLs below with your own resource values.175// Replace the illustrative IDs and URLs below with your own resource values.

176import OpenAI from "openai";176import OpenAI from "openai";

177const client = new OpenAI();177const client = new OpenAI();


267 267 

268Identify delegated command execution268Identify delegated command execution

269 269 

270```javascript270```typescript

271// Replace the illustrative session and turn IDs with values from your command item.271// Replace the illustrative session and turn IDs with values from your command item.

272import OpenAI from "openai";272import OpenAI from "openai";

273const client = new OpenAI();273const client = new OpenAI();

274 274 

275async function findTurn(sessionId, turnId) {275async function findTurn(sessionId: string, turnId: string) {

276 for await (const turn of client.beta.agents.sessions.turns.list(sessionId, {276 for await (const turn of client.beta.agents.sessions.turns.list(sessionId, {

277 limit: 100,277 limit: 100,

278 })) {278 })) {

Details

80 80 

81Configure managed-harness capabilities81Configure managed-harness capabilities

82 82 

83```javascript83```typescript

84import OpenAI from "openai";84import OpenAI from "openai";

85 85 

86const client = new OpenAI();86const client = new OpenAI();

Details

69 69

70 70 

71 71

72JavaScript72TypeScript

73 73 

74 74 

75Install the JavaScript SDK:75Use Node.js 22.6 or later and install the TypeScript SDK:

76 76 

77```bash77```bash

78npm install openai78npm install openai

79```79```

80 80 

81Save the example as `quickstart.mjs`:81Save the example as `quickstart.mts`:

82 82 

83Create and run tree.py83Create and run tree.py

84 84 

85```javascript85```typescript

86import OpenAI from "openai";86import OpenAI from "openai";

87 87 

88const client = new OpenAI();88const client = new OpenAI();


113Run it from your terminal:113Run it from your terminal:

114 114 

115```bash115```bash

116node quickstart.mjs116node --experimental-strip-types quickstart.mts

117```117```

118 118 

119 119


379 379

380 380 

381 381

382JavaScript382TypeScript

383 383 

384 Delete the session384 Delete the session

385 385 

386```javascript386```typescript

387// Replace the illustrative IDs and URLs below with your own resource values.387// Replace the illustrative IDs and URLs below with your own resource values.

388import OpenAI from "openai";388import OpenAI from "openai";

389 389 

390async function deleteSession(client, sessionId) {390async function deleteSession(client: OpenAI, sessionId: string) {

391 return client.beta.agents.sessions.delete(sessionId);391 return client.beta.agents.sessions.delete(sessionId);

392}392}

393 393 

Details

26 26 

27Create a session and stream its first turn27Create a session and stream its first turn

28 28 

29```javascript29```typescript

30import OpenAI from "openai";30import OpenAI from "openai";

31 31 

32const client = new OpenAI();32const client = new OpenAI();


231 231 

232Send a follow-up message232Send a follow-up message

233 233 

234```javascript234```typescript

235// Reuse the same submission key when retrying this message.235// Reuse the same submission key when retrying this message.

236async function sendMessage(client, sessionId, text, submissionKey) {236async function sendMessage(

237 client: OpenAI,

238 sessionId: string,

239 text: string,

240 submissionKey: string

241) {

237 await client.beta.agents.sessions.events.create(sessionId, {242 await client.beta.agents.sessions.events.create(sessionId, {

238 "Idempotency-Key": submissionKey,243 "Idempotency-Key": submissionKey,

239 events: [244 events: [


409 414 

410Retrieve session items415Retrieve session items

411 416 

412```javascript417```typescript

413// Pass your saved session ID to this helper.418// Pass your saved session ID to this helper.

414async function listItems(client, sessionId) {419async function listItems(client: OpenAI, sessionId: string) {

415 return client.beta.agents.sessions.items.list(sessionId, {420 return client.beta.agents.sessions.items.list(sessionId, {

416 order: "asc",421 order: "asc",

417 limit: 100,422 limit: 100,


486 491 

487Cancel the active turn492Cancel the active turn

488 493 

489```javascript494```typescript

490// Pass your saved session ID to this helper.495// Pass your saved session ID to this helper.

491async function cancelTurn(client, sessionId) {496async function cancelTurn(client: OpenAI, sessionId: string) {

492 await client.beta.agents.sessions.events.create(sessionId, {497 await client.beta.agents.sessions.events.create(sessionId, {

493 events: [{ type: "agent.session.input.cancel" }],498 events: [{ type: "agent.session.input.cancel" }],

494 });499 });

Details

179 179 

180Run npm install with automatic review180Run npm install with automatic review

181 181 

182```javascript182```typescript

183import OpenAI from "openai";183import OpenAI from "openai";

184 184 

185const client = new OpenAI();185const client = new OpenAI();


312 312 

313Turn off automatic review313Turn off automatic review

314 314 

315```javascript315```typescript

316const updatedSession = await client.beta.agents.sessions.update("sess_123", {316const updatedSession = await client.beta.agents.sessions.update("sess_123", {

317 review: "none",317 review: "none",

318});318});

Details

34 34 

35Automate sessions on a cron schedule35Automate sessions on a cron schedule

36 36 

37```javascript37```typescript

38import OpenAI from "openai";38import OpenAI from "openai";

39 39 

40const client = new OpenAI();40const client = new OpenAI();


242 242 

243 Enable agents to create automations243 Enable agents to create automations

244 244 

245```javascript245```typescript

246import OpenAI from "openai";246import OpenAI from "openai";

247 247 

248const client = new OpenAI();248const client = new OpenAI();


393 393 

394 Monitor automation invocations394 Monitor automation invocations

395 395 

396```javascript396```typescript

397import OpenAI from "openai";397import OpenAI from "openai";

398 398 

399const client = new OpenAI();399const client = new OpenAI();


569 569 

570### Restaurant reservations570### Restaurant reservations

571 571 

572```javascript572```typescript

573import OpenAI from "openai";573import OpenAI from "openai";

574 574 

575const client = new OpenAI();575const client = new OpenAI();


712 712 

713### Monthly spending713### Monthly spending

714 714 

715```javascript715```typescript

716import OpenAI from "openai";716import OpenAI from "openai";

717 717 

718const client = new OpenAI();718const client = new OpenAI();


920 920 

921### Daily actions921### Daily actions

922 922 

923```javascript923```typescript

924import OpenAI from "openai";924import OpenAI from "openai";

925 925 

926const client = new OpenAI();926const client = new OpenAI();


1166 1166 

1167Schedule daily suggestions1167Schedule daily suggestions

1168 1168 

1169```javascript1169```typescript

1170import OpenAI from "openai";1170import OpenAI from "openai";

1171 1171 

1172const client = new OpenAI();1172const client = new OpenAI();


1383 1383 

1384Schedule a monthly spending review1384Schedule a monthly spending review

1385 1385 

1386```javascript1386```typescript

1387import OpenAI from "openai";1387import OpenAI from "openai";

1388 1388 

1389const client = new OpenAI();1389const client = new OpenAI();


1615 1615 

1616Check restaurant reservations1616Check restaurant reservations

1617 1617 

1618```javascript1618```typescript

1619import OpenAI from "openai";1619import OpenAI from "openai";

1620 1620 

1621const client = new OpenAI();1621const client = new OpenAI();


1769 1769 

1770Schedule an agent to run once1770Schedule an agent to run once

1771 1771 

1772```javascript1772```typescript

1773import OpenAI from "openai";1773import OpenAI from "openai";

1774 1774 

1775const client = new OpenAI();1775const client = new OpenAI();


1913 1913 

1914Let agents schedule tasks1914Let agents schedule tasks

1915 1915 

1916```javascript1916```typescript

1917import OpenAI from "openai";1917import OpenAI from "openai";

1918 1918 

1919const client = new OpenAI();1919const client = new OpenAI();


2081 2081 

2082Schedule an onboarding follow-up2082Schedule an onboarding follow-up

2083 2083 

2084```javascript2084```typescript

2085import OpenAI from "openai";2085import OpenAI from "openai";

2086 2086 

2087const client = new OpenAI();2087const client = new OpenAI();


2240 2240 

2241Monitor automation invocations2241Monitor automation invocations

2242 2242 

2243```javascript2243```typescript

2244import OpenAI from "openai";2244import OpenAI from "openai";

2245 2245 

2246const client = new OpenAI();2246const client = new OpenAI();


2340 2340 

2341Change a schedule2341Change a schedule

2342 2342 

2343```javascript2343```typescript

2344import OpenAI from "openai";2344import OpenAI from "openai";

2345 2345 

2346const client = new OpenAI();2346const client = new OpenAI();

Details

20 20 

21Stream session events21Stream session events

22 22 

23```javascript23```typescript

24// Pass your saved session ID to this helper.24// Pass your saved session ID to this helper.

25async function streamSession(client, sessionId, handleEvent) {25async function streamSession(

26 client: OpenAI,

27 sessionId: string,

28 handleEvent: (

29 event: OpenAI.Beta.Agents.AgentSessionEvent

30 ) => void | Promise<void>

31) {

26 const events = await client.beta.agents.sessions.events.stream(sessionId);32 const events = await client.beta.agents.sessions.events.stream(sessionId);

27 try {33 try {

28 for await (const event of events) {34 for await (const event of events) {


202 208 

203Send and stream a message209Send and stream a message

204 210 

205```javascript211```typescript

206// Pass your saved session ID and message to this helper.212// Pass your saved session ID and message to this helper.

207async function sendAndStream(client, sessionId, text, handleEvent) {213async function sendAndStream(

214 client: OpenAI,

215 sessionId: string,

216 text: string,

217 handleEvent: (

218 event: OpenAI.Beta.Agents.AgentSessionEvent

219 ) => void | Promise<void>

220) {

208 const events = await client.beta.agents.sessions.events.stream(sessionId);221 const events = await client.beta.agents.sessions.events.stream(sessionId);

209 try {222 try {

210 await client.beta.agents.sessions.events.create(sessionId, {223 await client.beta.agents.sessions.events.create(sessionId, {

Details

13 13 

14List sessions and retrieve the next page14List sessions and retrieve the next page

15 15 

16```javascript16```typescript

17import OpenAI from "openai";17import OpenAI from "openai";

18 18 

19const client = new OpenAI();19const client = new OpenAI();


113 113 

114Retrieve a session114Retrieve a session

115 115 

116```javascript116```typescript

117// Pass your saved session ID to this helper.117// Pass your saved session ID to this helper.

118async function retrieveSession(client, sessionId) {118async function retrieveSession(client: OpenAI, sessionId: string) {

119 return client.beta.agents.sessions.retrieve(sessionId);119 return client.beta.agents.sessions.retrieve(sessionId);

120}120}

121```121```


181 181 

182Delete a session182Delete a session

183 183 

184```javascript184```typescript

185// Replace the illustrative IDs and URLs below with your own resource values.185// Replace the illustrative IDs and URLs below with your own resource values.

186import OpenAI from "openai";186import OpenAI from "openai";

187 187 

188async function deleteSession(client, sessionId) {188async function deleteSession(client: OpenAI, sessionId: string) {

189 return client.beta.agents.sessions.delete(sessionId);189 return client.beta.agents.sessions.delete(sessionId);

190}190}

191 191 

Details

87 87 

88Webhook handler88Webhook handler

89 89 

90```javascript90```typescript

91import express from "express";91import express from "express";

92import OpenAI from "openai";92import OpenAI from "openai";

93 93 

Details

21 21 

22Follow the [Agents API quickstart prerequisites](https://developers.openai.com/api/docs/guides/agents-api/quickstart#prerequisites)22Follow the [Agents API quickstart prerequisites](https://developers.openai.com/api/docs/guides/agents-api/quickstart#prerequisites)

23to create an API key and export `OPENAI_API_KEY`, then install the23to create an API key and export `OPENAI_API_KEY`, then install the

24[OpenAI SDK for your language](https://developers.openai.com/api/docs/libraries). For the JavaScript examples,24[OpenAI SDK for your language](https://developers.openai.com/api/docs/libraries). For the TypeScript examples,

25install `openai` and `prompt-sync`. The cURL examples require Bash and `jq`.25install `openai` and `prompt-sync`. The cURL examples require Bash and `jq`.

26 26 

27To enable browser access:27To enable browser access:


29- Add `{ "type": "computer_use" }` to `agent.tools`.29- Add `{ "type": "computer_use" }` to `agent.tools`.

30- Set `environment.type` to `openai_hosted` and `environment.desktop.enabled` to `true`.30- Set `environment.type` to `openai_hosted` and `environment.desktop.enabled` to `true`.

31 31 

32The JavaScript examples below form one walkthrough: create a session, handle32The TypeScript examples below form one walkthrough: create a session, handle

33website approvals, then send a task and print the answer. Start by creating a33website approvals, then send a task and print the answer. Start by creating a

34browser session with screenshots enabled. This does not start a task.34browser session with screenshots enabled. This does not start a task.

35 35 


60printf 'Session ID: %s\n' "$session_id"60printf 'Session ID: %s\n' "$session_id"

61```61```

62 62 

63```javascript63```typescript

64import OpenAI from "openai";64import OpenAI from "openai";

65import { open } from "node:fs/promises";65import { open } from "node:fs/promises";

66 66 


281 }'281 }'

282```282```

283 283 

284```javascript284```typescript

285import { createInterface } from "node:readline";285import { createInterface } from "node:readline";

286 286 

287const inputLines = createInterface({287const inputLines = createInterface({


291const answers = inputLines[Symbol.asyncIterator]();291const answers = inputLines[Symbol.asyncIterator]();

292 292 

293/** @param {OpenAI} client */293/** @param {OpenAI} client */

294async function respondToOriginApproval(client, sessionId, approval) {294async function respondToOriginApproval(

295 client: OpenAI,

296 sessionId: string,

297 approval: OpenAI.Beta.Agents.AgentSession.SessionRequiredActionResourceComputerUseApprovalRequest

298) {

295 const request = approval.request;299 const request = approval.request;

296 if (request.type === "browser_origin_access") {300 if (request.type === "browser_origin_access") {

297 console.log("Requested origin:", request.origin);301 console.log("Requested origin:", request.origin);


327 ],331 ],

328 });332 });

329 } else {333 } else {

330 throw new Error(`Unsupported approval request: ${request.type}`);334 throw new Error("Unsupported approval request");

331 }335 }

332}336}

333```337```


572 }'576 }'

573```577```

574 578 

575```javascript579```typescript

576let screenshot;580let screenshot;

577const events = await client.beta.agents.sessions.events.stream(session.id);581const events = await client.beta.agents.sessions.events.stream(session.id);

578const handledRequests = new Set();582const handledRequests = new Set();


1041# Use the returned last_id and keep order=asc on every page.1045# Use the returned last_id and keep order=asc on every page.

1042```1046```

1043 1047 

1044```javascript1048```typescript

1045for await (const item of client.beta.agents.sessions.items.list(session.id, {1049for await (const item of client.beta.agents.sessions.items.list(session.id, {

1046 order: "asc",1050 order: "asc",

1047 limit: 100,1051 limit: 100,


1351 --data-binary @browser-auth-response.json1355 --data-binary @browser-auth-response.json

1352```1356```

1353 1357 

1354```javascript1358```typescript

1355import promptSync from "prompt-sync";1359import promptSync from "prompt-sync";

1356 1360 

1357const prompt = promptSync({ sigint: true });1361const prompt = promptSync({ sigint: true });

1358 1362 

1359/** @param {OpenAI} client */1363/** @param {OpenAI} client */

1360async function respondToComputerUseApproval(client, sessionId, approval) {1364async function respondToComputerUseApproval(

1365 client: OpenAI,

1366 sessionId: string,

1367 approval: OpenAI.Beta.Agents.AgentSession.SessionRequiredActionResourceComputerUseApprovalRequest

1368) {

1361 const request = approval.request;1369 const request = approval.request;

1362 if (request.type === "browser_origin_access") {1370 if (request.type === "browser_origin_access") {

1363 console.log("Requested origin:", request.origin);1371 console.log("Requested origin:", request.origin);


1383 return;1391 return;

1384 }1392 }

1385 if (request.type !== "browser_authentication") {1393 if (request.type !== "browser_authentication") {

1386 throw new Error(`Unsupported approval request: ${request.type}`);1394 throw new Error("Unsupported approval request");

1387 }1395 }

1388 async function cancelSignIn() {1396 async function cancelSignIn() {

1389 await client.beta.agents.sessions.events.create(1397 await client.beta.agents.sessions.events.create(


1413 return;1421 return;

1414 }1422 }

1415 1423 

1416 let selectedOption;1424 let selectedOption: (typeof request.options)[number] | undefined;

1417 let activeFields = request.fields;1425 let activeFields = request.fields;

1418 if (request.options.length > 0) {1426 if (request.options.length > 0) {

1419 request.options.forEach((option, index) => {1427 request.options.forEach((option, index) => {


1434 choice < 1 ||1442 choice < 1 ||

1435 choice > request.options.length1443 choice > request.options.length

1436 );1444 );

1437 selectedOption = request.options[choice - 1];1445 const option = request.options[choice - 1];

1446 selectedOption = option;

1438 activeFields = request.fields.filter((field) =>1447 activeFields = request.fields.filter((field) =>

1439 selectedOption.field_ids.includes(field.id)1448 option.field_ids.includes(field.id)

1440 );1449 );

1441 }1450 }

1442 1451 


2139# Keep this stream open while responding to origin and sign-in approvals there.2148# Keep this stream open while responding to origin and sign-in approvals there.

2140```2149```

2141 2150 

2142```javascript2151```typescript

2143import OpenAI from "openai";2152import OpenAI from "openai";

2144 2153 

2145const client = new OpenAI();2154const client = new OpenAI();


2729 -H "Authorization: Bearer $OPENAI_API_KEY"2738 -H "Authorization: Bearer $OPENAI_API_KEY"

2730```2739```

2731 2740 

2732```javascript2741```typescript

2733await client.beta.agents.sessions.delete(session.id);2742await client.beta.agents.sessions.delete(session.id);

2734```2743```

2735 2744 

Details

67 67 

68Return a function result68Return a function result

69 69 

70```javascript70```typescript

71const result = {71const result = {

72 turn_id: action.turn_id,72 turn_id: action.turn_id,

73 call_id: action.call_id,73 call_id: action.call_id,

Details

60 60 

61Register a plugin61Register a plugin

62 62 

63```javascript63```typescript

64import OpenAI from "openai";64import OpenAI from "openai";

65const client = new OpenAI();65const client = new OpenAI();

66 66 

Details

37 37 

38Create a vault38Create a vault

39 39 

40```javascript40```typescript

41const vault = await client.beta.agents.vaults.create({41const vault = await client.beta.agents.vaults.create({

42 name: "GitHub credentials",42 name: "GitHub credentials",

43 metadata: {43 metadata: {


91 91 

92Store a bearer token92Store a bearer token

93 93 

94```javascript94```typescript

95// Replace the illustrative IDs and URLs below with your own resource values.95// Replace the illustrative IDs and URLs below with your own resource values.

96const vaultId = "vault_123";96const vaultId = "vault_123";

97const mcpUrl = "https://api.githubcopilot.com/mcp/";97const mcpUrl = "https://api.githubcopilot.com/mcp/";

98const accessToken = process.env.GITHUB_TOKEN;98const accessToken = process.env.GITHUB_TOKEN;

99 99 

100if (!accessToken) {

101 throw new Error("Set GITHUB_TOKEN");

102}

103 

100const credential = await client.beta.agents.vaults.credentials.create(vaultId, {104const credential = await client.beta.agents.vaults.credentials.create(vaultId, {

101 name: "GitHub access token",105 name: "GitHub access token",

102 auth: {106 auth: {


197 201 

198Attach the vault to a session202Attach the vault to a session

199 203 

200```javascript204```typescript

201// Replace the illustrative IDs and URLs below with your own resource values.205// Replace the illustrative IDs and URLs below with your own resource values.

202const mcpUrl = "https://api.githubcopilot.com/mcp/";206const mcpUrl = "https://api.githubcopilot.com/mcp/";

203const vaultId = "vault_123";207const vaultId = "vault_123";


424 428 

425Store an OAuth grant429Store an OAuth grant

426 430 

427```javascript431```typescript

428// Replace the illustrative expiry with your access token's actual expiry.432// Replace the illustrative expiry with your access token's actual expiry.

429// Replace the illustrative IDs and URLs below with your own resource values.433// Replace the illustrative IDs and URLs below with your own resource values.

430const vaultId = "vault_123";434const vaultId = "vault_123";


435const clientId = "example-client-id";439const clientId = "example-client-id";

436const refreshToken = process.env.OAUTH_REFRESH_TOKEN;440const refreshToken = process.env.OAUTH_REFRESH_TOKEN;

437 441 

442if (!accessToken || !refreshToken) {

443 throw new Error("Set OAUTH_ACCESS_TOKEN and OAUTH_REFRESH_TOKEN");

444}

445 

438const credential = await client.beta.agents.vaults.credentials.create(vaultId, {446const credential = await client.beta.agents.vaults.credentials.create(vaultId, {

439 name: "Example MCP OAuth credential",447 name: "Example MCP OAuth credential",

440 auth: {448 auth: {


605 613 

606Rotate an OAuth token614Rotate an OAuth token

607 615 

608```javascript616```typescript

609// Replace the illustrative expiry with your access token's actual expiry.617// Replace the illustrative expiry with your access token's actual expiry.

610// Replace the illustrative IDs and URLs below with your own resource values.618// Replace the illustrative IDs and URLs below with your own resource values.

611const credentialId = "cred_123";619const credentialId = "cred_123";

Details

27 27 

28Define a single agent28Define a single agent

29 29 

30```javascript30```typescript

31import { Agent, tool } from "@openai/agents";31import { Agent, tool } from "@openai/agents";

32import { z } from "zod";32import { z } from "zod";

33 33 


77 77 

78Return structured output78Return structured output

79 79 

80```javascript80```typescript

81import { Agent, run } from "@openai/agents";81import { Agent, run } from "@openai/agents";

82import { z } from "zod";82import { z } from "zod";

83 83 


140 140 

141Pass local context to tools141Pass local context to tools

142 142 

143```javascript143```typescript

144import { Agent, run, tool } from "@openai/agents";144import { Agent, run, tool, type RunContext } from "@openai/agents";

145import { z } from "zod";145import { z } from "zod";

146 146 

147const fetchUserAge = tool({147const fetchUserAge = tool({

148 name: "fetch_user_age",148 name: "fetch_user_age",

149 description: "Return the age of the current user.",149 description: "Return the age of the current user.",

150 parameters: z.object({}),150 parameters: z.object({}),

151 // TypeScript users can type this as RunContext<{ name: string; uid: number }>.151 async execute(

152 async execute(_args, runContext) {152 _args: unknown,

153 runContext: RunContext<{ name: string; uid: number }> | undefined

154 ) {

153 return `User ${runContext?.context.name} is 47 years old`;155 return `User ${runContext?.context.name} is 47 years old`;

154 },156 },

155});157});

Details

22 22 

23Block a request with an input guardrail23Block a request with an input guardrail

24 24 

25```javascript25```typescript

26import { Agent, InputGuardrailTripwireTriggered, run } from "@openai/agents";26import { Agent, InputGuardrailTripwireTriggered, run } from "@openai/agents";

27import { z } from "zod";27import { z } from "zod";

28 28 


133 133 

134Pause for approval before a sensitive action134Pause for approval before a sensitive action

135 135 

136```javascript136```typescript

137import { Agent, run, tool } from "@openai/agents";137import { Agent, run, tool } from "@openai/agents";

138import { z } from "zod";138import { z } from "zod";

139 139 

Details

20 20 

21Attach a hosted MCP server21Attach a hosted MCP server

22 22 

23```javascript23```typescript

24import { Agent, hostedMcpTool } from "@openai/agents";24import { Agent, hostedMcpTool } from "@openai/agents";

25 25 

26const agent = new Agent({26const agent = new Agent({


59 59 

60Connect a local MCP server60Connect a local MCP server

61 61 

62```javascript62```typescript

63import { Agent, MCPServerStdio, run } from "@openai/agents";63import { Agent, MCPServerStdio, run } from "@openai/agents";

64 64 

65const server = new MCPServerStdio({65const server = new MCPServerStdio({


140 140 

141Wrap multiple runs in one trace141Wrap multiple runs in one trace

142 142 

143```javascript143```typescript

144import { Agent, run, withTrace } from "@openai/agents";144import { Agent, run, withTrace } from "@openai/agents";

145 145 

146const agent = new Agent({146const agent = new Agent({

Details

14 14 

15Set models per agent and per run15Set models per agent and per run

16 16 

17```javascript17```typescript

18import { Agent, Runner } from "@openai/agents";18import { Agent, Runner } from "@openai/agents";

19 19 

20const fastAgent = new Agent({20const fastAgent = new Agent({

Details

17 17 

18Delegate with handoffs18Delegate with handoffs

19 19 

20```javascript20```typescript

21import { Agent, handoff } from "@openai/agents";21import { Agent, handoff } from "@openai/agents";

22 22 

23const billingAgent = new Agent({ name: "Billing agent" });23const billingAgent = new Agent({ name: "Billing agent" });


56 56 

57Call a specialist as a tool57Call a specialist as a tool

58 58 

59```javascript59```typescript

60import { Agent } from "@openai/agents";60import { Agent } from "@openai/agents";

61 61 

62const summarizer = new Agent({62const summarizer = new Agent({

Details

2 2 

3> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.3> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.

4 4 

5Use this page when you want the shortest path to a working SDK-based agent. The examples below use the same high-level concepts in both JavaScript and Python: define an agent, run it, then add tools and specialist agents as your workflow grows.5Use this page when you want the shortest path to a working SDK-based agent. The examples below use the same high-level concepts in both TypeScript and Python: define an agent, run it, then add tools and specialist agents as your workflow grows.

6 6 

7## Install the SDK7## Install the SDK

8 8 


14 14 

15 15 

16```bash16```bash

17# JavaScript17# TypeScript

18npm install @openai/agents zod18npm install @openai/agents zod

19 19 

20# Python20# Python


30 30 

31Create and run an agent31Create and run an agent

32 32 

33```javascript33```typescript

34import { Agent, run } from "@openai/agents";34import { Agent, run } from "@openai/agents";

35 35 

36const agent = new Agent({36const agent = new Agent({


86 86 

87Add a function tool87Add a function tool

88 88 

89```javascript89```typescript

90import { Agent, run, tool } from "@openai/agents";90import { Agent, run, tool } from "@openai/agents";

91import { z } from "zod";91import { z } from "zod";

92 92 


154 154 

155Route to specialist agents155Route to specialist agents

156 156 

157```javascript157```typescript

158import { Agent, run } from "@openai/agents";158import { Agent, run } from "@openai/agents";

159 159 

160const historyTutor = new Agent({160const historyTutor = new Agent({

Details

31 31 

32Persist multi-turn state with sessions32Persist multi-turn state with sessions

33 33 

34```javascript34```typescript

35import { Agent, MemorySession, run } from "@openai/agents";35import { Agent, MemorySession, run } from "@openai/agents";

36 36 

37const agent = new Agent({37const agent = new Agent({


88 88 

89Continue with server-managed state89Continue with server-managed state

90 90 

91```javascript91```typescript

92import { Agent, run } from "@openai/agents";92import { Agent, run } from "@openai/agents";

93import OpenAI from "openai";93import OpenAI from "openai";

94 94 


150 150 

151Stream a run as text arrives151Stream a run as text arrives

152 152 

153```javascript153```typescript

154import { Agent, run } from "@openai/agents";154import { Agent, run } from "@openai/agents";

155 155 

156const agent = new Agent({156const agent = new Agent({

Details

210 210 

211Load skills211Load skills

212 212 

213```javascript213```typescript

214import {214import {

215 Capabilities,215 Capabilities,

216 SandboxAgent,216 SandboxAgent,


290 290 

291Run a Unix-local sandbox agent291Run a Unix-local sandbox agent

292 292 

293```javascript293```typescript

294import { run } from "@openai/agents";294import { run } from "@openai/agents";

295import { Manifest, SandboxAgent, file, shell } from "@openai/agents/sandbox";295import { Manifest, SandboxAgent, file, shell } from "@openai/agents/sandbox";

296import { UnixLocalSandboxClient } from "@openai/agents/sandbox/local";296import { UnixLocalSandboxClient } from "@openai/agents/sandbox/local";


405 405 

406Switch to Docker406Switch to Docker

407 407 

408```javascript408```typescript

409import { run } from "@openai/agents";409import { run } from "@openai/agents";

410import { SandboxAgent } from "@openai/agents/sandbox";410import { SandboxAgent } from "@openai/agents/sandbox";

411import { DockerSandboxClient } from "@openai/agents/sandbox/local";411import { DockerSandboxClient } from "@openai/agents/sandbox/local";


504 504 

505Serialize and resume sandbox state505Serialize and resume sandbox state

506 506 

507```javascript507```typescript

508import { run } from "@openai/agents";508import { run } from "@openai/agents";

509import { Manifest, SandboxAgent } from "@openai/agents/sandbox";509import { Manifest, SandboxAgent } from "@openai/agents/sandbox";

510import { UnixLocalSandboxClient } from "@openai/agents/sandbox/local";510import { UnixLocalSandboxClient } from "@openai/agents/sandbox/local";


633 633 

634Enable sandbox memory634Enable sandbox memory

635 635 

636```javascript636```typescript

637import {637import {

638 Manifest,638 Manifest,

639 SandboxAgent,639 SandboxAgent,

Details

37Region and model ID for your deployment:37Region and model ID for your deployment:

38 38 

39- Client libraries with a Bedrock provider derive a regional Mantle base URL39- Client libraries with a Bedrock provider derive a regional Mantle base URL

40 from the AWS Region. The JavaScript, Python, Go, and Java providers use40 from the AWS Region. The TypeScript, Python, Go, and Java providers use

41 `https://bedrock-mantle.us-east-2.api.aws/openai/v1` for this guide's41 `https://bedrock-mantle.us-east-2.api.aws/openai/v1` for this guide's

42 `us-east-2` examples. The Ruby examples configure this `/openai/v1`42 `us-east-2` examples. The Ruby examples configure this `/openai/v1`

43 endpoint directly because the provider's default `/v1` route doesn't43 endpoint directly because the provider's default `/v1` route doesn't


66 66 

67Send a Responses API request through Amazon Bedrock67Send a Responses API request through Amazon Bedrock

68 68 

69```javascript69```typescript

70import OpenAI from "openai";70import OpenAI from "openai";

71import { bedrock } from "openai/providers/bedrock";71import { bedrock } from "openai/providers/bedrock";

72 72 


229 229 

230 230 

231For long-running applications, prefer the standard AWS credential chain instead231For long-running applications, prefer the standard AWS credential chain instead

232of a static bearer token. The JavaScript, Python, Go, Java, and Ruby SDK232of a static bearer token. The TypeScript, Python, Go, Java, and Ruby SDK

233providers resolve fresh AWS credentials and sign each request attempt with233providers resolve fresh AWS credentials and sign each request attempt with

234SigV4. The chain can include credentials configured with `aws login`, shared234SigV4. The chain can include credentials configured with `aws login`, shared

235profiles, workload roles, and instance or container credentials.235profiles, workload roles, and instance or container credentials.


251 251 

252Send a request with AWS-managed Bedrock credentials252Send a request with AWS-managed Bedrock credentials

253 253 

254```javascript254```typescript

255import OpenAI from "openai";255import OpenAI from "openai";

256import { defaultProvider } from "@aws-sdk/credential-provider-node";256import { defaultProvider } from "@aws-sdk/credential-provider-node";

257import { bedrock } from "openai/providers/bedrock/aws";257import { bedrock } from "openai/providers/bedrock/aws";

Details

26 26 

27Run a weather lookup in the background27Run a weather lookup in the background

28 28 

29```javascript29```typescript

30import OpenAI from "openai";30import OpenAI from "openai";

31 31 

32const client = new OpenAI();32const client = new OpenAI();

33const model = "gpt-6-astra";33const model = "gpt-6-astra";

34 34 

35const tools = [35const tools: OpenAI.Responses.Tool[] = [

36 {36 {

37 type: "function",37 type: "function",

38 name: "get_weather",38 name: "get_weather",


47 },47 },

48 },48 },

49];49];

50async function getWeather(city) {50async function getWeather(city: string) {

51 const snapshots = {51 const snapshots = {

52 Paris: {52 Paris: {

53 city: "Paris",53 city: "Paris",


59 if (typeof city !== "string" || !Object.hasOwn(snapshots, city)) {59 if (typeof city !== "string" || !Object.hasOwn(snapshots, city)) {

60 throw new Error(`No demo weather snapshot for ${city}.`);60 throw new Error(`No demo weather snapshot for ${city}.`);

61 }61 }

62 return snapshots[city];62 return snapshots[city as keyof typeof snapshots];

63}63}

64const instructions =64const instructions =

65 "Start the weather lookup and answer the independent packing question " +65 "Start the weather lookup and answer the independent packing question " +

Details

14 14 

15 Create a human-like audio response to a prompt15 Create a human-like audio response to a prompt

16 16 

17```javascript17```typescript

18import { writeFileSync } from "node:fs";18import { writeFileSync } from "node:fs";

19import OpenAI from "openai";19import OpenAI from "openai";

20 20 


38console.log(response.choices[0]);38console.log(response.choices[0]);

39 39 

40// Write audio data to a file40// Write audio data to a file

41writeFileSync(41const audio = response.choices[0].message.audio;

42 "dog.wav",42if (!audio) throw new Error("The response did not include audio.");

43 Buffer.from(response.choices[0].message.audio.data, "base64"),43writeFileSync("dog.wav", Buffer.from(audio.data, "base64"), {

44 { encoding: "utf-8" }44 encoding: "utf-8",

45);45});

46```46```

47 47 

48```python48```python


212 212 

213 Use audio inputs for prompting a model213 Use audio inputs for prompting a model

214 214 

215```javascript215```typescript

216import OpenAI from "openai";216import OpenAI from "openai";

217const openai = new OpenAI();217const openai = new OpenAI();

218 218 

Details

31}'31}'

32```32```

33 33 

34```javascript34```typescript

35import OpenAI from "openai";35import OpenAI from "openai";

36const client = new OpenAI();36const client = new OpenAI();

37 37 


149 -H "Authorization: Bearer $OPENAI_API_KEY"149 -H "Authorization: Bearer $OPENAI_API_KEY"

150```150```

151 151 

152```javascript152```typescript

153import OpenAI from "openai";153import OpenAI from "openai";

154const client = new OpenAI();154const client = new OpenAI();

155 155 


319 -H "Authorization: Bearer $OPENAI_API_KEY"319 -H "Authorization: Bearer $OPENAI_API_KEY"

320```320```

321 321 

322```javascript322```typescript

323import OpenAI from "openai";323import OpenAI from "openai";

324const client = new OpenAI();324const client = new OpenAI();

325 325 


426-H "Authorization: Bearer $OPENAI_API_KEY"426-H "Authorization: Bearer $OPENAI_API_KEY"

427```427```

428 428 

429```javascript429```typescript

430import OpenAI from "openai";430import OpenAI from "openai";

431const client = new OpenAI();431const client = new OpenAI();

432 432 

guides/batch.md +7 −7

Details

62 62 

63Upload files for Batch API63Upload files for Batch API

64 64 

65```javascript65```typescript

66import fs from "fs";66import fs from "fs";

67import OpenAI from "openai";67import OpenAI from "openai";

68const openai = new OpenAI();68const openai = new OpenAI();


166 166 

167Create the Batch167Create the Batch

168 168 

169```javascript169```typescript

170import OpenAI from "openai";170import OpenAI from "openai";

171const openai = new OpenAI();171const openai = new OpenAI();

172 172 


294 294 

295Check the status of a batch295Check the status of a batch

296 296 

297```javascript297```typescript

298import OpenAI from "openai";298import OpenAI from "openai";

299const openai = new OpenAI();299const openai = new OpenAI();

300 300 


377 377 

378Retrieving the batch results378Retrieving the batch results

379 379 

380```javascript380```typescript

381import OpenAI from "openai";381import OpenAI from "openai";

382const openai = new OpenAI();382const openai = new OpenAI();

383 383 


484 484 

485Cancelling a batch485Cancelling a batch

486 486 

487```javascript487```typescript

488import OpenAI from "openai";488import OpenAI from "openai";

489const openai = new OpenAI();489const openai = new OpenAI();

490 490 


559 559 

560Getting a list of all batches560Getting a list of all batches

561 561 

562```javascript562```typescript

563import OpenAI from "openai";563import OpenAI from "openai";

564const openai = new OpenAI();564const openai = new OpenAI();

565 565 


635 635 

636## Model availability636## Model availability

637 637 

638Most models support the Batch API. Check the [model reference](https://developers.openai.com/api/docs/models) for your model. GPT-6 Sol and Luna support EU data residency with Standard, Flex, and Batch processing. See [data residency eligibility](https://developers.openai.com/api/docs/guides/your-data#which-models-and-features-are-eligible-for-data-residency).638Most models support the Batch API. Check the [model reference](https://developers.openai.com/api/docs/models) for your model. GPT-6 Sol and Luna support EU data residency with Standard, Flex, and Batch processing. See [data residency eligibility](https://developers.openai.com/api/docs/guides/data-residency#which-models-and-features-are-eligible-for-data-residency).

639 639 

640GPT-Image-2.5 supports batch image generation and editing with `gpt-image-2.5-flare` and `gpt-image-2.5-sunburst`, including their `2026-09-08` snapshots. Use `/v1/images/generations` or `/v1/images/edits` and see [image generation pricing](https://developers.openai.com/api/docs/pricing?multimodal-image-pricing=batch#image-generation) for Batch rates.640GPT-Image-2.5 supports batch image generation and editing with `gpt-image-2.5-flare` and `gpt-image-2.5-sunburst`, including their `2026-09-08` snapshots. Use `/v1/images/generations` or `/v1/images/edits` and see [image generation pricing](https://developers.openai.com/api/docs/pricing?multimodal-image-pricing=batch#image-generation) for Batch rates.

641 641 

Details

192 192 

193 Create a ChatKit session token193 Create a ChatKit session token

194 194 

195```javascript195```typescript

196export default async function getChatKitSessionToken(deviceId) {196export default async function getChatKitSessionToken(deviceId: string) {

197 const apiKey = process.env.OPENAI_API_KEY;197 const apiKey = process.env.OPENAI_API_KEY;

198 if (!apiKey) {198 if (!apiKey) {

199 throw new Error("OPENAI_API_KEY is required");199 throw new Error("OPENAI_API_KEY is required");


292```292```

293 293 

294 294 

2955. Render ChatKit in your UI. Pass the React `MyChat` component a `getAppAuthToken` function that returns the current user's bearer token. If you use the JavaScript tab, make the same function available in the snippet's scope. This code sends that credential to your server, fetches the client secret, and mounts a live chat widget connected to your workflow.2955. Render ChatKit in your UI. Pass the React `MyChat` component a `getAppAuthToken` function that returns the current user's bearer token. If you use the TypeScript tab, make the same function available in the snippet's scope. This code sends that credential to your server, fetches the client secret, and mounts a live chat widget connected to your workflow.

296 296 

297 Your frontend code297 Your frontend code

298 298 

299```javascript299```typescript

300const chatkit = document.getElementById("my-chat");300const chatkit = document.getElementById("my-chat");

301if (301if (

302 !chatkit ||302 !chatkit ||

Details

21```21```

22 22 

23 23 

24Actions can also be sent imperatively by your frontend with `sendAction()`. This is probably most useful when you need ChatKit to respond to interaction happening outside ChatKit, but it can also be used to chain actions when you need to respond on both the client and the server (more on that below).24Actions can also be sent imperatively by your frontend with `sendCustomAction()`. This is probably most useful when you need ChatKit to respond to interaction happening outside ChatKit, but it can also be used to chain actions when you need to respond on both the client and the server (more on that below).

25 25 

26```javascript26```typescript

27await chatKit.sendAction({27await chatKit.sendCustomAction({

28 type: "example",28 type: "example",

29 payload: { id: 123 },29 payload: { id: 123 },

30});30});


85 85 

86Then, when the action is triggered, it will then be passed to a callback that you provide when instantiating ChatKit.86Then, when the action is triggered, it will then be passed to a callback that you provide when instantiating ChatKit.

87 87 

88```javascript88```typescript

89async function handleWidgetAction(action) {89async function handleWidgetAction(action: { type: string }) {

90 if (action.type === "example") {90 if (action.type === "example") {

91 const res = await doSomething(action);91 const res = await doSomething(action);

92 92 

93 // You can fire off actions to your server from here as well.93 // You can fire off actions to your server from here as well.

94 // For example, stream new thread items or update a widget.94 // For example, stream new thread items or update a widget.

95 await chatKit.sendAction({95 await chatKit.sendCustomAction({

96 type: "example_complete",96 type: "example_complete",

97 payload: res,97 payload: res,

98 });98 });

Details

57 57 

58For all theming options, see the [API reference](https://openai.github.io/chatkit-js/api/openai/chatkit/type-aliases/themeoption/).58For all theming options, see the [API reference](https://openai.github.io/chatkit-js/api/openai/chatkit/type-aliases/themeoption/).

59 59 

60```javascript60```typescript

61const options = {61import type { ChatKitOptions } from "@openai/chatkit";

62 

63const options: Partial<ChatKitOptions> = {

62 theme: {64 theme: {

63 colorScheme: "dark",65 colorScheme: "dark",

64 color: {66 color: {


79 81 

80Let users know what to ask or guide their first input by changing the composer’s placeholder text.82Let users know what to ask or guide their first input by changing the composer’s placeholder text.

81 83 

82```javascript84```typescript

83const options = {85const options: Partial<ChatKitOptions> = {

84 composer: {86 composer: {

85 placeholder: "Ask anything about your data…",87 placeholder: "Ask anything about your data…",

86 },88 },


95 97 

96Guide users on what to ask or do by suggesting prompt ideas when starting a conversation.98Guide users on what to ask or do by suggesting prompt ideas when starting a conversation.

97 99 

98```javascript100```typescript

99const options = {101const options: Partial<ChatKitOptions> = {

100 startScreen: {102 startScreen: {

101 greeting: "What can I help you build today?",103 greeting: "What can I help you build today?",

102 prompts: [104 prompts: [

103 {105 {

104 name: "Check on the status of a ticket",106 label: "Check on the status of a ticket",

105 prompt: "Can you help me check on the status of a ticket?",107 prompt: "Can you help me check on the status of a ticket?",

106 icon: "search",108 icon: "search",

107 },109 },

108 {110 {

109 name: "Create Ticket",111 label: "Create Ticket",

110 prompt: "Can you help me create a new support ticket?",112 prompt: "Can you help me create a new support ticket?",

111 icon: "write",113 icon: "write",

112 },114 },


120 122 

121Custom header buttons help you add navigation, context, or actions relevant to your integration.123Custom header buttons help you add navigation, context, or actions relevant to your integration.

122 124 

123```javascript125```typescript

124const options = {126const options: Partial<ChatKitOptions> = {

125 header: {127 header: {

126 customButtonLeft: {128 leftAction: {

127 icon: "settings-cog",129 icon: "settings-cog",

128 onClick: () => openProfileSettings(),130 onClick: () => openProfileSettings(),

129 },131 },

130 customButtonRight: {132 rightAction: {

131 icon: "home",133 icon: "home",

132 onClick: () => openHomePage(),134 onClick: () => openHomePage(),

133 },135 },


144 146 

145You can also control the number, size, and types of files that users can attach to messages.147You can also control the number, size, and types of files that users can attach to messages.

146 148 

147```javascript149```typescript

148const options = {150const options: Partial<ChatKitOptions> = {

149 composer: {151 composer: {

150 attachments: {152 attachments: {

151 uploadStrategy: { type: "hosted" },153 enabled: true,

152 maxSize: 20 * 1024 * 1024, // 20 MB per file154 maxSize: 20 * 1024 * 1024, // 20 MB per file

153 maxCount: 3,155 maxCount: 3,

154 accept: { "application/pdf": [".pdf"], "image/*": [".png", ".jpg"] },156 accept: { "application/pdf": [".pdf"], "image/*": [".png", ".jpg"] },


165- Use `onTagSearch` to return a list of entities based on the input query.167- Use `onTagSearch` to return a list of entities based on the input query.

166- Use `onClick` to handle the click event of an entity.168- Use `onClick` to handle the click event of an entity.

167 169 

168```javascript170```typescript

169const options = {171const options: Partial<ChatKitOptions> = {

170 entities: {172 entities: {

171 async onTagSearch(query) {173 async onTagSearch(query) {

172 void query;174 void query;


203 205 

204 206 

205 207 

206```javascript208```typescript

207const options = {209const options: Partial<ChatKitOptions> = {

208 entities: {210 entities: {

209 async onTagSearch() {211 async onTagSearch() {

210 return [];212 return [];

211 },213 },

212 onRequestPreview: async (entity) => ({214 onRequestPreview: async (entity) => ({

213 preview: {215 preview: {

214 type: "Card",216 type: "Basic",

215 children: [217 children: [

216 { type: "Text", value: `Profile: ${entity.title}` },218 { type: "Text", value: `Profile: ${entity.title}` },

217 { type: "Text", value: "Role: Developer" },219 { type: "Text", value: "Role: Developer" },


228Enhance productivity by letting users trigger app-specific actions from the composer bar. The selected tool230Enhance productivity by letting users trigger app-specific actions from the composer bar. The selected tool

229will be sent to the model as a tool preference.231will be sent to the model as a tool preference.

230 232 

231```javascript233```typescript

232const options = {234const options: Partial<ChatKitOptions> = {

233 composer: {235 composer: {

234 tools: [236 tools: [

235 {237 {


248 250 

249Disable major UI regions and features if you need more customization over the options available in the header and want to implement your own instead. Disabling history can be useful when the concept of threads and history doesn't make sense for your use case—e.g., in a support chatbot.251Disable major UI regions and features if you need more customization over the options available in the header and want to implement your own instead. Disabling history can be useful when the concept of threads and history doesn't make sense for your use case—e.g., in a support chatbot.

250 252 

251```javascript253```typescript

252const options = {254const options: Partial<ChatKitOptions> = {

253 history: { enabled: false },255 history: { enabled: false },

254 header: { enabled: false },256 header: { enabled: false },

255};257};


260 262 

261Override the default locale if you have an app-wide language setting. By default, the locale is set to the browser's locale.263Override the default locale if you have an app-wide language setting. By default, the locale is set to the browser's locale.

262 264 

263```javascript265```typescript

264const options = {266const options: Partial<ChatKitOptions> = {

265 locale: "de-DE",267 locale: "de-DE",

266};268};

267```269```

Details

22 22 

23Capture widget events with the `onAction` callback from `WidgetsOption` or equivalent React hook. Forward the action payload to your backend to handle actions.23Capture widget events with the `onAction` callback from `WidgetsOption` or equivalent React hook. Forward the action payload to your backend to handle actions.

24 24 

25```javascript25```typescript

26chatkit.setOptions({26chatkit.setOptions({

27 widgets: {27 widgets: {

28 async onAction(action, item) {28 async onAction(action, item) {

Details

224 224 

225Citation parsing helpers225Citation parsing helpers

226 226 

227```javascript227```typescript

228const CITATION_START = "\uE200";228const CITATION_START = "\uE200";

229const CITATION_DELIMITER = "\uE202";229const CITATION_DELIMITER = "\uE202";

230const CITATION_STOP = "\uE201";230const CITATION_STOP = "\uE201";


237// {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_STOP}237// {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_STOP}

238// {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_DELIMITER}L8-L13{CITATION_STOP}238// {CITATION_START}cite{CITATION_DELIMITER}turn0file0{CITATION_DELIMITER}L8-L13{CITATION_STOP}

239// {CITATION_START}cite{CITATION_DELIMITER}turn0search0{CITATION_DELIMITER}turn1news2{CITATION_STOP}239// {CITATION_START}cite{CITATION_DELIMITER}turn0search0{CITATION_DELIMITER}turn1news2{CITATION_STOP}

240function extractCitations(text, { families = ["cite"] } = {}) {240function extractCitations(text: string, { families = ["cite"] } = {}) {

241 if (families.length === 0) {241 if (families.length === 0) {

242 return [];242 return [];

243 }243 }


257 const body = match.groups?.body ?? "";257 const body = match.groups?.body ?? "";

258 const parts = body258 const parts = body

259 .split(CITATION_DELIMITER)259 .split(CITATION_DELIMITER)

260 .map((part) => part.trim())260 .map((part: string) => part.trim())

261 .filter(Boolean);261 .filter(Boolean);

262 262 

263 if (parts.length === 0) {263 if (parts.length === 0) {


270 locator = parts.pop() ?? null;270 locator = parts.pop() ?? null;

271 }271 }

272 272 

273 if (parts.length === 0 || parts.some((part) => !SOURCE_ID_RE.test(part))) {273 if (

274 parts.length === 0 ||

275 parts.some((part: string) => !SOURCE_ID_RE.test(part))

276 ) {

274 continue;277 continue;

275 }278 }

276 279 


287 return citations;290 return citations;

288}291}

289 292 

290function stripCitations(text, citations) {293function stripCitations(

294 text: string,

295 citations: ReturnType<typeof extractCitations>

296) {

291 let cleanText = text;297 let cleanText = text;

292 const sortedCitations = Array.from(citations).sort(298 const sortedCitations = Array.from(citations).sort(

293 (left, right) => right.start - left.start299 (left, right) => right.start - left.start

Details

29 29 

30Default model for most coding tasks30Default model for most coding tasks

31 31 

32```javascript32```typescript

33import OpenAI from "openai";33import OpenAI from "openai";

34const openai = new OpenAI();34const openai = new OpenAI();

35 35 

Details

54 54 

55## Example user flow55## Example user flow

56 56 

57```javascript57```typescript

58import OpenAI from "openai";58import OpenAI from "openai";

59import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";59import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

60import { createInterface } from "node:readline";60import { createInterface } from "node:readline";

61 61 

62const client = new OpenAI();62const client = new OpenAI();

63 63 

64const conversation = [64const conversation: OpenAI.Responses.ResponseInput = [

65 {65 {

66 type: "message",66 type: "message",

67 role: "user",67 role: "user",


314 314 

315### Example user flow315### Example user flow

316 316 

317```javascript317```typescript

318import OpenAI from "openai";318import OpenAI from "openai";

319import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

319 320 

320const client = new OpenAI();321const client = new OpenAI();

321 322 

322const conversation = [{ role: "user", content: "Plan a trip to Kyoto." }];323const conversation: OpenAI.Responses.ResponseInput = [

324 { role: "user", content: "Plan a trip to Kyoto." },

325];

323 326 

324const compacted = await client.responses.compact({327const compacted = await client.responses.compact({

325 model: "gpt-6-astra",328 model: "gpt-6-astra",

326 input: conversation,329 input: conversation,

327});330});

328 331 

329const nextInput = [332const nextInput: OpenAI.Responses.ResponseInput = [

330 ...compacted.output.map((item) => item),333 ...toResponseInputItems(compacted.output),

331 { role: "user", content: "Add two more days to the itinerary." },334 { role: "user", content: "Add two more days to the itinerary." },

332];335];

333 336 

Details

16 16 

17An example legacy Completions API call looks like the following:17An example legacy Completions API call looks like the following:

18 18 

19```javascript19```typescript

20const completion = await openai.completions.create({20const completion = await openai.completions.create({

21 model: "gpt-3.5-turbo-instruct",21 model: "gpt-3.5-turbo-instruct",

22 prompt: "Write a tagline for an ice cream shop.",22 prompt: "Write a tagline for an ice cream shop.",

Details

53 53 

54Verify an image54Verify an image

55 55 

56```javascript56```typescript

57import { createReadStream } from "node:fs";57import { createReadStream } from "node:fs";

58import OpenAI, { toStreamingFile } from "openai";58import OpenAI, { toStreamingFile } from "openai";

59 59 

Details

19 19 

20 Manually construct a past conversation20 Manually construct a past conversation

21 21 

22```javascript22```typescript

23import OpenAI from "openai";23import OpenAI from "openai";

24 24 

25const openai = new OpenAI();25const openai = new OpenAI();


184 184 

185 Manually manage conversation state with the Responses API.185 Manually manage conversation state with the Responses API.

186 186 

187```javascript187```typescript

188import OpenAI from "openai";188import OpenAI from "openai";

189import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";189import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

190 190 

191const openai = new OpenAI();191const openai = new OpenAI();

192 192 

193let history = [193let history: OpenAI.Responses.ResponseInput = [

194 {194 {

195 role: "user",195 role: "user",

196 content: "tell me a joke",196 content: "tell me a joke",


449 449 

450 Create a conversation450 Create a conversation

451 451 

452```javascript452```typescript

453const conversation = await client.conversations.create();453const conversation = await client.conversations.create();

454```454```

455 455 


482 482 

483 Manage conversation state with Conversations and Responses APIs483 Manage conversation state with Conversations and Responses APIs

484 484 

485```javascript485```typescript

486const response = await client.responses.create({486const response = await client.responses.create({

487 model: "gpt-6-astra",487 model: "gpt-6-astra",

488 input: [{ role: "user", content: "What are the five Ds of dodgeball?" }],488 input: [{ role: "user", content: "What are the five Ds of dodgeball?" }],


557 557 

558 Chain responses across turns by passing the previous response ID558 Chain responses across turns by passing the previous response ID

559 559 

560```javascript560```typescript

561import OpenAI from "openai";561import OpenAI from "openai";

562 562 

563const openai = new OpenAI();563const openai = new OpenAI();

Details

206 206 

207ChatKit emits `CustomEvent` instances from the Web Component. Listen for lifecycle events and read payload data from `event.detail`:207ChatKit emits `CustomEvent` instances from the Web Component. Listen for lifecycle events and read payload data from `event.detail`:

208 208 

209```javascript209```typescript

210chatkit.addEventListener("chatkit.error", (event) => {210chatkit.addEventListener("chatkit.error", (event) => {

211 console.error(event.detail.error);211 console.error(event.detail.error);

212});212});

Details

126 126 

127For [WebRTC](https://developers.openai.com/api/docs/guides/voice-webrtc?api=live), include this configuration in the JSON `session` field alongside `transport`. For [WebSockets](https://developers.openai.com/api/docs/guides/voice-websockets?api=live), include it in the first `session.start` event. Follow the connection guide to send audio and hear the voice. Choose the voice at startup; start a new session to try a different voice.127For [WebRTC](https://developers.openai.com/api/docs/guides/voice-webrtc?api=live), include this configuration in the JSON `session` field alongside `transport`. For [WebSockets](https://developers.openai.com/api/docs/guides/voice-websockets?api=live), include it in the first `session.start` event. Follow the connection guide to send audio and hear the voice. Choose the voice at startup; start a new session to try a different voice.

128 128 

129Voice creation through `/v1/audio/voices`, including creation from recordings, isn't compatible with Zero Data Retention. GPT-Live speech generations are eligible for Zero Data Retention when it's enabled for your organization or project. Stored session recordings, recording downloads, and session forking aren't available with Zero Data Retention. See the [data controls](https://developers.openai.com/api/docs/guides/your-data#v1livesessions) for session storage and retention requirements.129Voice creation through `/v1/audio/voices`, including creation from recordings, isn't compatible with Zero Data Retention. GPT-Live speech generations are eligible for Zero Data Retention when it's enabled for your organization or project. Stored session recordings, recording downloads, and session forking aren't available with Zero Data Retention. See the [data controls](https://developers.openai.com/api/docs/guides/data-residency#v1livesessions) for session storage and retention requirements.

130 130 

131### Refine and reuse131### Refine and reuse

132 132 


247 247 

248Use the following request body when [creating a Realtime client secret](https://developers.openai.com/api/reference/resources/realtime/subresources/client_secrets/methods/create), then follow the [WebRTC connection guide](https://developers.openai.com/api/docs/guides/voice-webrtc?api=realtime) to connect with that secret. Replace `voice_123abc` with the ID returned by your voice creation request:248Use the following request body when [creating a Realtime client secret](https://developers.openai.com/api/reference/resources/realtime/subresources/client_secrets/methods/create), then follow the [WebRTC connection guide](https://developers.openai.com/api/docs/guides/voice-webrtc?api=realtime) to connect with that secret. Replace `voice_123abc` with the ID returned by your voice creation request:

249 249 

250```javascript250```typescript

251const sessionConfig = JSON.stringify({251const sessionConfig = JSON.stringify({

252 session: {252 session: {

253 type: "realtime",253 type: "realtime",

guides/data-residency.md +224 −0 created

Details

1# Data residency

2 

3> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.

4 

5<span

6 id="data-residency-controls"

7 className="scroll-mt-[var(--docs-scroll-offset)]"

8>

9 

10 

11Data residency is a project configuration option that lets you choose the location of infrastructure OpenAI uses to provide services.

12 

13Eligible organizations can [enable data residency](#how-to-use-data-residency) when creating a project in the API Platform. Data residency endpoints are charged a [10% uplift](https://developers.openai.com/api/docs/pricing) for models released on or after March 5, 2026, that are eligible for data residency.

14 

15## How does data residency work?

16 

17You can select an available region when creating a project.

18 

19- **Storage:** For supported endpoints, models, and snapshots, your Customer Content (as defined in your services agreement) is stored at rest in the selected region when the endpoint requires persistence, such as `/v1/batches`.

20- **Processing:** If the region supports regional processing, inference for your Customer Content also runs in that region.

21- **System data:** Data residency does not apply to system data, which may be stored and processed outside the selected region. This is account data, metadata, and usage data without Customer Content, collected to manage and operate the services. Examples include account information or profiles of end users who directly access the services, analytics, usage statistics, billing information, support requests, and structured output schema.

22 

23## Sub-processors and regional request processing

24 

25OpenAI uses [sub-processors](https://openai.com/policies/sub-processor-list/) to provide its services. For requests sent to `us.api.openai.com`, `eu.api.openai.com`, `au.api.openai.com`, `in.api.openai.com`, or `jp.api.openai.com`, OpenAI uses [Cloudflare Regional Services](https://developers.cloudflare.com/data-localization/regional-services/) so that TLS termination and HTTPS decryption occur within the selected processing region.

26 

27## Limitations

28 

29Data residency does not apply to:

30 

311. Any transmission or storage of Customer Content outside of the selected region caused by the location of an End User or Customer’s infrastructure when accessing the services.

322. Products, services, or content offered by parties other than OpenAI through the Services.

333. Any data other than Customer Content, such as system data.

34 

35If your selected Region does not support regional processing, as identified below, OpenAI may also process and temporarily store Customer Content outside of the Region to deliver the services.

36 

37## How to use data residency

38 

39Data residency is configured per-project within your API Organization. As an organization owner:

40 

411. Open the [Projects page](https://platform.openai.com/settings/organization/projects) in the API Platform and select **Create**.

422. Enter a project name and, under **Data and inference residency**, select an available region.

433. Select **Create**, then create an API key for the new project.

444. Use that project's API key with the regional domain prefix listed in the table below, such as `eu.api.openai.com` for Europe.

45 

46The project's residency region can't be changed after creation. To select a different region, create a new project.

47 

48### Select a processing region per request

49 

50To enable per-request data residency for a new Global project, follow the creation steps above, leave **Data and inference residency** set to **Global**, and select **Enable per-request data residency** before selecting **Create**. The project remains Global.

51 

52Use an API key from that Global project with a regional domain prefix for each request that needs regional processing. The selected endpoint and model must support regional processing, as shown in the table below.

53 

54If your existing Global project already supports per-request data residency, you can continue using its API keys.

55 

56The following example reuses one client and an API key from a Global project for global, US, and EU requests:

57 

58```python

59from openai import OpenAI

60 

61client = OpenAI()

62 

63# No processing constraint.

64response = client.responses.create(

65 model="gpt-5.6-terra",

66 input="Reply with OK.",

67)

68print(response.output_text)

69 

70# US processing and storage.

71response = client.with_options(

72 base_url="https://us.api.openai.com/v1",

73).responses.create(

74 model="gpt-5.6-terra",

75 input="Reply with OK.",

76)

77print(response.output_text)

78 

79# EU processing and storage.

80response = client.with_options(

81 base_url="https://eu.api.openai.com/v1",

82).responses.create(

83 model="gpt-5.6-terra",

84 input="Reply with OK.",

85)

86print(response.output_text)

87```

88 

89```ruby

90require "openai"

91 

92client = OpenAI::Client.new

93 

94response = client.responses.create(

95 model: "gpt-5.6-terra",

96 input: "Reply with OK."

97)

98puts(response.output_text)

99 

100response = client.with_options(data_residency: :us).responses.create(

101 model: "gpt-5.6-terra",

102 input: "Reply with OK."

103)

104puts(response.output_text)

105 

106# EU processing requires a key from an EU-region project.

107response = client.with_options(data_residency: :eu, api_key: ENV.fetch("OPENAI_EU_API_KEY"), organization: nil, project: nil).responses.create(

108 model: "gpt-5.6-terra",

109 input: "Reply with OK."

110)

111puts(response.output_text)

112```

113 

114 

115## Which models and features are eligible for data residency?

116 

117The following models and API services are eligible for data residency today for the regions specified below.

118 

119Use **Support by region** to compare regional capabilities and expand the services available in each region. Use **API Endpoint, tool and model support** for complete model lists and a detailed service view. Support for regional storage does not imply support for regional processing.

120 

121In Australia, India, and Japan, `gpt-6-luna` supports regional processing. These regions support Standard pay-as-you-go only. Use a project in the selected region. The Responses and Chat Completions APIs support text and image inputs and text output. Hosted tools are unavailable for regional processing in these three regions.

122 

123Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna. Fast mode is not available with EU data residency for GPT-6 Astra or GPT-6 Sol. GPT-6.1 Sol, GPT-6.1 Terra, GPT-6 Sol, and GPT-6 Luna support EU data residency with Standard, Flex, and Batch processing. [Ultrafast mode](https://developers.openai.com/api/docs/guides/ultrafast-mode) for GPT-6.1 Sol supports US and EU data residency and global processing. GPT-6 Astra Ultrafast supports US data residency and global processing only.

124 

125### Support by region

126 

127The complete, unfiltered regional support table follows. Model snapshots for each service are listed in **API Endpoint, tool and model support**. When regional processing supports only a subset of snapshots, that subset is included in the processing-services cell.

128 

129| Region | Domain prefix | Regional storage | Regional processing | Additional access requirements | Supported modes | Storage services | Processing services |

130| -------------------------- | ------------------- | :--------------: | :-----------------: | :---------------------------------------------------------------------------------------------------------------------------: | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

131| United States | `us.api.openai.com` | Yes | Yes | — | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/evals`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/live/sessions`<br />`/v1/realtime`<br />`/v1/realtime/transcription_sessions`<br />`/v1/realtime/translations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/evals`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/live/sessions`<br />`/v1/realtime`<br />`/v1/realtime/transcription_sessions`<br />`/v1/realtime/translations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`Code Interpreter tool`<br />`File Search`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` |

132| Europe (EEA + Switzerland) | `eu.api.openai.com` | Yes | Yes | — | Text, Audio, Voice, Image\* | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/evals`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/live/sessions`<br />`/v1/realtime`<br />`/v1/realtime/transcription_sessions`<br />`/v1/realtime/translations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/evals`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/live/sessions`<br />`/v1/realtime`<br />`/v1/realtime/transcription_sessions`<br />`/v1/realtime/translations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`Code Interpreter tool`<br />`File Search`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` |

133| Australia\* | `au.api.openai.com` | Yes | Yes | — | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/chat/completions` (`gpt-6-luna`)<br />`/v1/responses` (`gpt-6-luna`) |

134| Canada\* | `ca.api.openai.com` | Yes | No | — | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | None |

135| Japan\* | `jp.api.openai.com` | Yes | Yes | — | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/chat/completions` (`gpt-6-luna`)<br />`/v1/responses` (`gpt-6-luna`) |

136| India\* | `in.api.openai.com` | Yes | Yes | [Contact sales](https://openai.com/contact-sales/) to access this region | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/chat/completions` (`gpt-6-luna`)<br />`/v1/responses` (`gpt-6-luna`) |

137| Singapore\* | `sg.api.openai.com` | Yes | No | — | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | None |

138| South Korea\* | `kr.api.openai.com` | Yes | No | — | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | None |

139| United Kingdom\* | `gb.api.openai.com` | Yes | No | — | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | None |

140| United Arab Emirates\* | `ae.api.openai.com` | Yes | Yes | [Contact sales](https://openai.com/contact-sales/) to access this region | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/chat/completions` (`gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.2-2025-12-11`)<br />`/v1/embeddings` (`text-embedding-3-large`)<br />`/v1/responses` (`gpt-5.5-pro-2026-04-23`, `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.2-2025-12-11`) |

141 

142\* Image support in these regions requires additional approval. [Contact sales](https://openai.com/contact-sales/).

143 

144### API Endpoint, tool and model support

145 

146| Endpoint or feature | Service | Storage regions | Processing regions | Supported models and snapshots | Regional processing snapshot exceptions | Notes |

147| -------------------------------------------------------------------- | ---------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

148| `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech` | Audio | All listed regions | United States, Europe (EEA + Switzerland) | `tts-1`, `whisper-1`, `gpt-4o-tts`, `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, `gpt-transcribe` | None | — |

149| `/v1/batches` | Batches | All listed regions | United States, Europe (EEA + Switzerland) | `gpt-6-astra`, `gpt-6.1-sol`, `gpt-6.1-terra`, `gpt-6-sol`, `gpt-6-luna`, `gpt-5.5-pro-2026-04-23`, `gpt-5.4-pro-2026-03-05`, `gpt-5.2-pro-2025-12-11`, `gpt-5-pro-2025-10-06`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.4-2026-03-05`, `gpt-5-2025-08-07`, `gpt-5.4-mini-2026-03-17`, `gpt-5.4-nano-2026-03-17`, `gpt-5.2-2025-12-11`, `gpt-5.1-2025-11-13`, `gpt-5-mini-2025-08-07`, `gpt-5-nano-2025-08-07`, `gpt-4.1-2025-04-14`, `gpt-4.1-mini-2025-04-14`, `gpt-4.1-nano-2025-04-14`, `o3-2025-04-16`, `o4-mini-2025-04-16`, `o1-pro`, `o1-pro-2025-03-19`, `o3-mini-2025-01-31`, `o1-2024-12-17`, `gpt-4o-2024-11-20`, `gpt-4o-2024-08-06`, `gpt-4o-mini-2024-07-18`, `gpt-4-turbo-2024-04-09`, `gpt-4-0613`, `gpt-3.5-turbo-0125` | None | GPT-6.1 Sol, GPT-6.1 Terra, GPT-6 Sol, and GPT-6 Luna support EU data residency with Standard, Flex, and Batch processing. GPT-6.1 Sol and GPT-6.1 Terra support only US and EU data residency. |

150| `/v1/chat/completions` | Chat Completions | All listed regions | United States, Europe (EEA + Switzerland), United Arab Emirates, Australia, India, Japan | `gpt-6-astra`, `gpt-6.1-sol`, `gpt-6.1-terra`, `gpt-6-sol`, `gpt-6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.4-2026-03-05`, `gpt-5.4-mini-2026-03-17`, `gpt-5.4-nano-2026-03-17`, `gpt-5.2-2025-12-11`, `gpt-5.1-2025-11-13`, `gpt-5-2025-08-07`, `gpt-5-mini-2025-08-07`, `gpt-5-nano-2025-08-07`, `gpt-4.1-2025-04-14`, `gpt-4.1-mini-2025-04-14`, `gpt-4.1-nano-2025-04-14`, `o3-mini-2025-01-31`, `o3-2025-04-16`, `o4-mini-2025-04-16`, `o1-2024-12-17`, `gpt-4o-2024-11-20`, `gpt-4o-2024-08-06`, `gpt-4o-mini-2024-07-18`, `gpt-4-turbo-2024-04-09`, `gpt-4-0613`, `gpt-3.5-turbo-0125` | United Arab Emirates: `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.2-2025-12-11`<br />Australia, India, Japan: `gpt-6-luna` | Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna. Fast mode is not available with EU data residency for GPT-6 Astra or GPT-6 Sol. GPT-6.1 Sol and GPT-6.1 Terra support only US and EU data residency. |

151| `/v1/decisions` | Decisions | All listed regions | United States, Europe (EEA + Switzerland) | `gpt-6-luna` | None | Available in all supported API regions. Regional processing is supported in the United States and Europe (EEA + Switzerland). Prompt caching is subject to the retention limitations below. |

152| `/v1/embeddings` | Embeddings | All listed regions | United States, Europe (EEA + Switzerland), United Arab Emirates | `text-embedding-3-small`, `text-embedding-3-large`, `text-embedding-ada-002` | United Arab Emirates: `text-embedding-3-large` | — |

153| `/v1/evals` | Evals | United States, Europe (EEA + Switzerland) | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

154| `/v1/files` | Files | All listed regions | None | Service-level support | None | — |

155| `/v1/fine_tuning/jobs` | Fine-tuning | All listed regions | United States, Europe (EEA + Switzerland) | `gpt-4o-2024-08-06`, `gpt-4o-mini-2024-07-18`, `gpt-4.1-2025-04-14`, `gpt-4.1-mini-2025-04-14` | None | — |

156| `/v1/images/edits` | Images | All listed regions | United States, Europe (EEA + Switzerland) | `gpt-image-2.5-sunburst`, `gpt-image-2.5-sunburst-2026-09-08`, `gpt-image-2.5-flare`, `gpt-image-2.5-flare-2026-09-08`, `gpt-image-2`, `gpt-image-1.5`, `gpt-image-1-mini` | None | — |

157| `/v1/images/generations` | Images | All listed regions | United States, Europe (EEA + Switzerland) | `gpt-image-2.5-sunburst`, `gpt-image-2.5-sunburst-2026-09-08`, `gpt-image-2.5-flare`, `gpt-image-2.5-flare-2026-09-08`, `gpt-image-2`, `gpt-image-1.5`, `gpt-image-1-mini` | None | — |

158| `/v1/moderations` | Moderation | All listed regions | United States, Europe (EEA + Switzerland) | `omni-moderation-latest` | None | — |

159| `/v1/live/sessions` | GPT-Live | United States, Europe (EEA + Switzerland) | United States, Europe (EEA + Switzerland) | `gpt-live-1` | None | — |

160| `/v1/realtime` | Realtime | United States, Europe (EEA + Switzerland) | United States, Europe (EEA + Switzerland) | `gpt-realtime`, `gpt-realtime-1.5`, `gpt-realtime-mini`, `gpt-realtime-2`, `gpt-realtime-2.1`, `gpt-realtime-2.1-mini` | None | — |

161| `/v1/realtime/transcription_sessions` | Realtime | United States, Europe (EEA + Switzerland) | United States, Europe (EEA + Switzerland) | `gpt-realtime-whisper`, `gpt-live-transcribe`, `gpt-transcribe` | None | — |

162| `/v1/realtime/translations` | Realtime | United States, Europe (EEA + Switzerland) | United States, Europe (EEA + Switzerland) | `gpt-realtime-translate` | None | — |

163| `/v1/responses` | Responses | All listed regions | United States, Europe (EEA + Switzerland), United Arab Emirates, Australia, India, Japan | `gpt-6-astra`, `gpt-6.1-sol`, `gpt-6.1-terra`, `gpt-6-sol`, `gpt-6-luna`, `gpt-5.5-pro-2026-04-23`, `gpt-5.4-pro-2026-03-05`, `gpt-5.2-pro-2025-12-11`, `gpt-5-pro-2025-10-06`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.4-2026-03-05`, `gpt-5-2025-08-07`, `gpt-5.4-mini-2026-03-17`, `gpt-5.4-nano-2026-03-17`, `gpt-5.2-2025-12-11`, `gpt-5.1-2025-11-13`, `gpt-5-mini-2025-08-07`, `gpt-5-nano-2025-08-07`, `gpt-4.1-2025-04-14`, `gpt-4.1-mini-2025-04-14`, `gpt-4.1-nano-2025-04-14`, `o3-2025-04-16`, `o4-mini-2025-04-16`, `o1-pro`, `o1-pro-2025-03-19`, `o3-mini-2025-01-31`, `o1-2024-12-17`, `gpt-4o-2024-11-20`, `gpt-4o-2024-08-06`, `gpt-4o-mini-2024-07-18`, `gpt-4-turbo-2024-04-09`, `gpt-4-0613`, `gpt-3.5-turbo-0125` | United Arab Emirates: `gpt-5.5-pro-2026-04-23`, `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.2-2025-12-11`<br />Australia, India, Japan: `gpt-6-luna` | Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna. Fast mode is not available with EU data residency for GPT-6 Astra or GPT-6 Sol. GPT-6.1 Sol and GPT-6.1 Terra support only US and EU data residency. |

164| `/v1/responses File Search` | Responses | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

165| `/v1/responses Web Search` | Responses | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

166| `/v1/vector_stores` | Vector stores | All listed regions | None | Service-level support | None | — |

167| `Code Interpreter tool` | Tools | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

168| `File Search` | Tools | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

169| `File Uploads` | Files | All listed regions | None | Service-level support | None | Supported when used with base64 file uploads. |

170| `Remote MCP server tool` | Tools | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | MCP servers are third-party services. Data sent to an MCP server is subject to its data residency policies. |

171| `Scale Tier` | Other | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

172| `Structured Outputs (excluding schema)` | Other | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

173| `Supported input modalities` | Other | All listed regions | United States, Europe (EEA + Switzerland) | `Text`, `Image`, `Audio/Voice` | None | — |

174 

175 

176 

177## Endpoint limitations

178 

179<span

180 id="v1decisions-1"

181 className="scroll-mt-[var(--docs-scroll-offset)]"

182>

183 

184 

185### /v1/decisions

186 

187The Decisions API is available in all supported API regions. Regional processing is supported in the United States and Europe (EEA + Switzerland). Availability in a region does not imply that inference is performed in that region.

188 

189- [Extended prompt caching](https://developers.openai.com/api/docs/guides/prompt-caching#prompt-cache-retention) in regions that do not support Regional processing may require that OpenAI process and temporarily store Customer Content outside of the Region to deliver the services.

190 

191<span

192 id="v1chatcompletions-1"

193 className="scroll-mt-[var(--docs-scroll-offset)]"

194>

195 

196 

197### /v1/chat/completions

198 

199- Cannot set store=true in non-US regions.

200- [Extended prompt caching](https://developers.openai.com/api/docs/guides/prompt-caching#prompt-cache-retention) in regions that do not support Regional processing may require that OpenAI process and temporarily store Customer Content outside of the Region to deliver the services.

201 

202<span

203 id="v1responses-1"

204 className="scroll-mt-[var(--docs-scroll-offset)]"

205>

206 

207 

208### /v1/responses

209 

210- [Extended prompt caching](https://developers.openai.com/api/docs/guides/prompt-caching#prompt-cache-retention) in regions that do not support Regional processing may require that OpenAI process and temporarily store Customer Content outside of the Region to deliver the services.

211 

212### /v1/live/sessions

213 

214GPT-Live sessions are eligible for Zero Data Retention. With Zero Data Retention enabled, `store` is treated as `false`, even if a request sets it to `true`.

215 

216Session storage is disabled by default. For projects with session storage enabled, `store: true` retains the completed session recording for 30 days so that it can be downloaded or used to start a forked session. Stored sessions and their index expire after 30 days. Recording downloads and forking require a data policy that permits persistence and are not available with Zero Data Retention.

217 

218Setting `store: false` on a fork prevents storage of the new session; it does not delete the source recording or remove the authorization required to read it. The API does not provide a public stored-session deletion endpoint.

219 

220GPT-Live supports data residency in the United States and Europe. Delegated backend models and tools have their own data controls; check the applicable endpoint and feature entries on this page.

221 

222### /v1/realtime

223 

224Tracing is not currently EU data residency compliant for `/v1/realtime`.

Details

137JSON137JSON

138```138```

139 139 

140```javascript140```typescript

141import { readFile } from "node:fs/promises";141import { readFile } from "node:fs/promises";

142import OpenAI from "openai";142import OpenAI from "openai";

143 143 


442 442 

443A `choice` question selects one value from the options you provide. Use distinct values and descriptions that explain when each option applies.443A `choice` question selects one value from the options you provide. Use distinct values and descriptions that explain when each option applies.

444 444 

445The model sees each choice's `value` and its `description`, when provided. Both fields are part of the prompt, so changing a `value` can change the result even when its description stays the same.

446 

447When choosing a string `value`, prefer meaningful labels such as `"billing"` and `"technical"` over opaque identifiers such as a UUID.

448 

449Keep choice descriptions concise and direct, as in the examples below.

450 

445 451 

446 452 

447This request routes a customer complaint:453This request routes a customer complaint:


469 }'475 }'

470```476```

471 477 

472```javascript478```typescript

473import OpenAI from "openai";479import OpenAI from "openai";

474 480 

475const client = new OpenAI();481const client = new OpenAI();


735 }'741 }'

736```742```

737 743 

738```javascript744```typescript

739import OpenAI from "openai";745import OpenAI from "openai";

740 746 

741const client = new OpenAI();747const client = new OpenAI();

Details

51When reasoning effort is not `none`, remove `temperature`, `top_p`, and51When reasoning effort is not `none`, remove `temperature`, `top_p`, and

52`top_logprobs`; also remove `logprobs` from Chat Completions requests and52`top_logprobs`; also remove `logprobs` from Chat Completions requests and

53`message.output_text.logprobs` from the Responses `include` array. Check53`message.output_text.logprobs` from the Responses `include` array. Check

54[data residency eligibility](https://developers.openai.com/api/docs/guides/your-data#which-models-and-features-are-eligible-for-data-residency)54[data residency eligibility](https://developers.openai.com/api/docs/guides/data-residency#which-models-and-features-are-eligible-for-data-residency)

55before selecting a model or processing tier. See the55before selecting a model or processing tier. See the

56[model migration guidance](https://developers.openai.com/api/docs/guides/latest-model?model=gpt-6-astra#migration-quickstart)56[model migration guidance](https://developers.openai.com/api/docs/guides/latest-model?model=gpt-6-astra#migration-quickstart)

57for other compatibility checks. Run representative evals before changing prompts or adding new57for other compatibility checks. Run representative evals before changing prompts or adding new


86 86 

87Tune reasoning effort for the task87Tune reasoning effort for the task

88 88 

89```javascript89```typescript

90import OpenAI from "openai";90import OpenAI from "openai";

91 91 

92const openai = new OpenAI();92const openai = new OpenAI();


256 256 

257Set lower verbosity for compact output257Set lower verbosity for compact output

258 258 

259```javascript259```typescript

260import OpenAI from "openai";260import OpenAI from "openai";

261 261 

262const openai = new OpenAI();262const openai = new OpenAI();


450 450 

451Use hosted tool search with deferred tools451Use hosted tool search with deferred tools

452 452 

453```javascript453```typescript

454import OpenAI from "openai";454import OpenAI from "openai";

455 455 

456const openai = new OpenAI();456const openai = new OpenAI();

457 457 

458const billingNamespace = {458const billingNamespace: OpenAI.Responses.NamespaceTool = {

459 type: "namespace",459 type: "namespace",

460 name: "billing",460 name: "billing",

461 description: "Billing tools for invoices, payments, taxes, and credits.",461 description: "Billing tools for invoices, payments, taxes, and credits.",


479 ],479 ],

480};480};

481 481 

482const crmNamespace = {482const crmNamespace: OpenAI.Responses.NamespaceTool = {

483 type: "namespace",483 type: "namespace",

484 name: "crm",484 name: "crm",

485 description:485 description:


876 876 

877Continue from compacted response state877Continue from compacted response state

878 878 

879```javascript879```typescript

880import OpenAI from "openai";880import OpenAI from "openai";

881import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";881import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

882 882 


1129 1129 

1130Maintain separate cache accounting for a customer1130Maintain separate cache accounting for a customer

1131 1131 

1132```javascript1132```typescript

1133import OpenAI from "openai";1133import OpenAI from "openai";

1134 1134 

1135const openai = new OpenAI();1135const openai = new OpenAI();


1295 1295 

1296Pass encrypted reasoning between stateless turns1296Pass encrypted reasoning between stateless turns

1297 1297 

1298```javascript1298```typescript

1299import OpenAI from "openai";1299import OpenAI from "openai";

1300import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";1300import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

1301 1301 

1302const openai = new OpenAI();1302const openai = new OpenAI();

1303 1303 

1304const history = [1304const history: OpenAI.Responses.ResponseInput = [

1305 {1305 {

1306 role: "user",1306 role: "user",

1307 content: "Investigate why invoice INV-1043 has mismatched tax totals.",1307 content: "Investigate why invoice INV-1043 has mismatched tax totals.",


1591 1591 

1592Run and poll a background response1592Run and poll a background response

1593 1593 

1594```javascript1594```typescript

1595// Replace the illustrative IDs and URLs below with your own resource values.1595// Replace the illustrative IDs and URLs below with your own resource values.

1596import OpenAI from "openai";1596import OpenAI from "openai";

1597 1597 


1614 ],1614 ],

1615});1615});

1616 1616 

1617while (["queued", "in_progress"].includes(job.status)) {1617while (job.status === "queued" || job.status === "in_progress") {

1618 await new Promise((resolve) => setTimeout(resolve, 2000));1618 await new Promise((resolve) => setTimeout(resolve, 2000));

1619 job = await openai.responses.retrieve(job.id);1619 job = await openai.responses.retrieve(job.id);

1620}1620}


1797only stored in memory.1797only stored in memory.

1798 1798 

1799The Python sample uses `pip install "openai[realtime]>=3.8.0"`.1799The Python sample uses `pip install "openai[realtime]>=3.8.0"`.

1800The JavaScript sample uses `npm install openai@^7.10.0 ws`.1800The TypeScript sample uses `npm install openai@^7.10.0 ws`.

1801The Ruby sample uses `gem install openai async-websocket`.1801The Ruby sample uses `gem install openai async-websocket`.

1802 1802 

1803For Go, run `go get github.com/openai/openai-go/v3@v3.98.0`.1803For Go, run `go get github.com/openai/openai-go/v3@v3.98.0`.


1806 1806 

1807Start a Responses API WebSocket session1807Start a Responses API WebSocket session

1808 1808 

1809```javascript1809```typescript

1810import OpenAI from "openai";1810import OpenAI from "openai";

1811import { ResponsesWS } from "openai/resources/responses/ws";1811import { ResponsesWS } from "openai/resources/responses/ws";

1812 1812 

1813const testLogTool = {1813const testLogTool: OpenAI.Responses.FunctionTool = {

1814 type: "function",1814 type: "function",

1815 name: "search_test_logs",1815 name: "search_test_logs",

1816 description: "Search test logs for a query.",1816 description: "Search test logs for a query.",


1823 strict: true,1823 strict: true,

1824};1824};

1825 1825 

1826const codeSearchTool = {1826const codeSearchTool: OpenAI.Responses.FunctionTool = {

1827 type: "function",1827 type: "function",

1828 name: "search_code",1828 name: "search_code",

1829 description: "Search the codebase for a query.",1829 description: "Search the codebase for a query.",

Details

104 104 

105Create a fine-tuning job with DPO105Create a fine-tuning job with DPO

106 106 

107```javascript107```typescript

108import OpenAI from "openai";108import OpenAI from "openai";

109 109 

110const openai = new OpenAI();110const openai = new OpenAI();

Details

23 23 

24Example: Getting embeddings24Example: Getting embeddings

25 25 

26```javascript26```typescript

27import OpenAI from "openai";27import OpenAI from "openai";

28const openai = new OpenAI();28const openai = new OpenAI();

29 29 


191 191 

192 192 

193Get_embeddings_from_dataset.ipynb193Get_embeddings_from_dataset.ipynb

194```javascript194```typescript

195import { mkdir, writeFile } from "node:fs/promises";195import { mkdir, writeFile } from "node:fs/promises";

196import OpenAI from "openai";196import OpenAI from "openai";

197 197 


203 input: reviews.map((review) => review.replaceAll("\n", " ")),203 input: reviews.map((review) => review.replaceAll("\n", " ")),

204});204});

205 205 

206const csvField = (value) => `"${value.replaceAll('"', '""')}"`;206const csvField = (value: string) => `"${value.replaceAll('"', '""')}"`;

207const rows = response.data.map(({ embedding }, index) =>207const rows = response.data.map(({ embedding }, index) =>

208 [csvField(reviews[index]), csvField(JSON.stringify(embedding))].join(",")208 [csvField(reviews[index]), csvField(JSON.stringify(embedding))].join(",")

209);209);


418 418 

419In general, using the `dimensions` parameter when creating the embedding is the suggested approach. In certain cases, you may need to change the embedding dimension after you generate it. When you change the dimension manually, you need to be sure to normalize the dimensions of the embedding as is shown below.419In general, using the `dimensions` parameter when creating the embedding is the suggested approach. In certain cases, you may need to change the embedding dimension after you generate it. When you change the dimension manually, you need to be sure to normalize the dimensions of the embedding as is shown below.

420 420 

421```javascript421```typescript

422import OpenAI from "openai";422import OpenAI from "openai";

423 423 

424const client = new OpenAI();424const client = new OpenAI();


553 553 

554There are many common cases where the model is not trained on data which contains key facts and information you want to make accessible when generating responses to a user query. One way of solving this, as shown below, is to put additional information into the context window of the model. This is effective in many use cases but leads to higher token costs. In this notebook, we explore the tradeoff between this approach and embeddings bases search.554There are many common cases where the model is not trained on data which contains key facts and information you want to make accessible when generating responses to a user query. One way of solving this, as shown below, is to put additional information into the context window of the model. This is effective in many use cases but leads to higher token costs. In this notebook, we explore the tradeoff between this approach and embeddings bases search.

555 555 

556```javascript556```typescript

557import OpenAI from "openai";557import OpenAI from "openai";

558 558 

559const client = new OpenAI();559const client = new OpenAI();


731 731 

732To retrieve the most relevant documents we use the cosine similarity between the embedding vectors of the query and each document, and return the highest scored documents.732To retrieve the most relevant documents we use the cosine similarity between the embedding vectors of the query and each document, and return the highest scored documents.

733 733 

734```javascript734```typescript

735import OpenAI from "openai";735import OpenAI from "openai";

736 736 

737const client = new OpenAI();737const client = new OpenAI();


746 input: [...reviews, "delicious beans"],746 input: [...reviews, "delicious beans"],

747});747});

748 748 

749const query = data.at(-1).embedding;749const query = data[reviews.length].embedding;

750const similarity = (embedding) => {750const similarity = (embedding: number[]) => {

751 const dotProduct = embedding.reduce(751 const dotProduct = embedding.reduce(

752 (total, value, index) => total + value * query[index],752 (total, value, index) => total + value * query[index],

753 0753 0


993 993 

994To perform a code search, we embed the query in natural language using the same model. Then we calculate cosine similarity between the resulting query embedding and each of the function embeddings. The highest cosine similarity results are most relevant.994To perform a code search, we embed the query in natural language using the same model. Then we calculate cosine similarity between the resulting query embedding and each of the function embeddings. The highest cosine similarity results are most relevant.

995 995 

996```javascript996```typescript

997import OpenAI from "openai";997import OpenAI from "openai";

998 998 

999const client = new OpenAI();999const client = new OpenAI();


1007 input: [...functions, "Completions API tests"],1007 input: [...functions, "Completions API tests"],

1008});1008});

1009 1009 

1010const query = data.at(-1).embedding;1010const query = data[functions.length].embedding;

1011const similarity = (embedding) => {1011const similarity = (embedding: number[]) => {

1012 const dotProduct = embedding.reduce(1012 const dotProduct = embedding.reduce(

1013 (total, value, index) => total + value * query[index],1013 (total, value, index) => total + value * query[index],

1014 01014 0


1256 1256 

1257Below, we illustrate a basic recommender. It takes in a list of strings and one 'source' string, computes their embeddings, and then returns a ranking of the strings, ranked from most similar to least similar. As a concrete example, the linked notebook below applies a version of this function to the [AG news dataset](http://groups.di.unipi.it/~gulli/AG_corpus_of_news_articles.html) (sampled down to 2,000 news article descriptions) to return the top 5 most similar articles to any given source article.1257Below, we illustrate a basic recommender. It takes in a list of strings and one 'source' string, computes their embeddings, and then returns a ranking of the strings, ranked from most similar to least similar. As a concrete example, the linked notebook below applies a version of this function to the [AG news dataset](http://groups.di.unipi.it/~gulli/AG_corpus_of_news_articles.html) (sampled down to 2,000 news article descriptions) to return the top 5 most similar articles to any given source article.

1258 1258 

1259```javascript1259```typescript

1260import OpenAI from "openai";1260import OpenAI from "openai";

1261 1261 

1262const client = new OpenAI();1262const client = new OpenAI();


1667 1667 

1668We can use embeddings for zero shot classification without any labeled training data. For each class, we embed the class name or a short description of the class. To classify some new text in a zero-shot manner, we compare its embedding to all class embeddings and predict the class with the highest similarity.1668We can use embeddings for zero shot classification without any labeled training data. For each class, we embed the class name or a short description of the class. To classify some new text in a zero-shot manner, we compare its embedding to all class embeddings and predict the class with the highest similarity.

1669 1669 

1670```javascript1670```typescript

1671import OpenAI from "openai";1671import OpenAI from "openai";

1672 1672 

1673const client = new OpenAI();1673const client = new OpenAI();


1678 input: [...labels, "The coffee arrived quickly and tastes great."],1678 input: [...labels, "The coffee arrived quickly and tastes great."],

1679});1679});

1680 1680 

1681const review = data.at(-1).embedding;1681const review = data[labels.length].embedding;

1682const similarity = (embedding) => {1682const similarity = (embedding: number[]) => {

1683 const dotProduct = embedding.reduce(1683 const dotProduct = embedding.reduce(

1684 (total, value, index) => total + value * review[index],1684 (total, value, index) => total + value * review[index],

1685 01685 0

Details

373 373 

374We advise you to programmatically handle errors returned by the API. To do so, you may want to use a code snippet like below:374We advise you to programmatically handle errors returned by the API. To do so, you may want to use a code snippet like below:

375 375 

376```javascript376```typescript

377import OpenAI from "openai";377import OpenAI from "openai";

378 378 

379const client = new OpenAI();379const client = new OpenAI();

guides/evals.md +5 −5

Details

34 34 

35 Categorize IT support tickets35 Categorize IT support tickets

36 36 

37```javascript37```typescript

38import OpenAI from "openai";38import OpenAI from "openai";

39const client = new OpenAI();39const client = new OpenAI();

40 40 


217 217 

218Create an eval218Create an eval

219 219 

220```javascript220```typescript

221import OpenAI from "openai";221import OpenAI from "openai";

222const openai = new OpenAI();222const openai = new OpenAI();

223 223 


497 497 

498Upload a test data file498Upload a test data file

499 499 

500```javascript500```typescript

501import fs from "fs";501import fs from "fs";

502import OpenAI from "openai";502import OpenAI from "openai";

503 503 


613 613 

614 Create an eval run614 Create an eval run

615 615 

616```javascript616```typescript

617import OpenAI from "openai";617import OpenAI from "openai";

618const openai = new OpenAI();618const openai = new OpenAI();

619 619 


848 848 

849Retrieve eval run status849Retrieve eval run status

850 850 

851```javascript851```typescript

852import OpenAI from "openai";852import OpenAI from "openai";

853const openai = new OpenAI();853const openai = new OpenAI();

854 854 

Details

19 19 

20Create a response with Fast mode20Create a response with Fast mode

21 21 

22```javascript22```typescript

23import OpenAI from "openai";23import OpenAI from "openai";

24 24 

25const openai = new OpenAI();25const openai = new OpenAI();

Details

103 103 

104Use an external file URL104Use an external file URL

105 105 

106```javascript106```typescript

107import OpenAI from "openai";107import OpenAI from "openai";

108const client = new OpenAI();108const client = new OpenAI();

109 109 


325 325 

326Upload a file326Upload a file

327 327 

328```javascript328```typescript

329import fs from "fs";329import fs from "fs";

330import OpenAI from "openai";330import OpenAI from "openai";

331const client = new OpenAI();331const client = new OpenAI();


593 593 

594Send a Base64-encoded file594Send a Base64-encoded file

595 595 

596```javascript596```typescript

597import fs from "fs";597import fs from "fs";

598import OpenAI from "openai";598import OpenAI from "openai";

599const client = new OpenAI();599const client = new OpenAI();

Details

59 59 

60Setting hyperparameters60Setting hyperparameters

61 61 

62```javascript62```typescript

63const fineTune = await openai.fineTuning.jobs.create({63const fineTune = await openai.fineTuning.jobs.create({

64 training_file: "file-abc123",64 training_file: "file-abc123",

65 model: "gpt-4o-mini-2024-07-18",65 model: "gpt-4o-mini-2024-07-18",

Details

16 16 

17 Flex processing example17 Flex processing example

18 18 

19```javascript19```typescript

20import OpenAI from "openai";20import OpenAI from "openai";

21const client = new OpenAI({21const client = new OpenAI({

22 timeout: 15 * 1000 * 60, // Increase default timeout to 15 minutes22 timeout: 15 * 1000 * 60, // Increase default timeout to 15 minutes


163Due to slower processing speeds with Flex processing, request timeouts are more likely. Here are some considerations for handling timeouts:163Due to slower processing speeds with Flex processing, request timeouts are more likely. Here are some considerations for handling timeouts:

164 164 

165- **Default timeout**: The default timeout is **10 minutes** when making API requests with an official OpenAI SDK. You may need to increase this timeout for lengthy prompts or complex tasks.165- **Default timeout**: The default timeout is **10 minutes** when making API requests with an official OpenAI SDK. You may need to increase this timeout for lengthy prompts or complex tasks.

166- **Configuring timeouts**: Each SDK will provide a parameter to increase this timeout. In the Python and JavaScript SDKs, this is `timeout` as shown in the code samples above.166- **Configuring timeouts**: Each SDK will provide a parameter to increase this timeout. In the Python and TypeScript SDKs, this is `timeout` as shown in the code samples above.

167- **Automatic retries**: The OpenAI SDKs automatically retry requests that result in a `408 Request Timeout` error code twice before throwing an exception.167- **Automatic retries**: The OpenAI SDKs automatically retry requests that result in a `408 Request Timeout` error code twice before throwing an exception.

168 168 

169## Resource unavailable errors169## Resource unavailable errors

Details

114 114 

115 Complete tool calling example115 Complete tool calling example

116 116 

117```javascript117```typescript

118import OpenAI from "openai";118import OpenAI from "openai";

119import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";119import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

120 120 


122 122 

123// 1. Define a list of callable tools for the model123// 1. Define a list of callable tools for the model

124 124 

125const tools = [125const tools: OpenAI.Responses.Tool[] = [

126 {126 {

127 type: "function",127 type: "function",

128 name: "get_horoscope",128 name: "get_horoscope",


142 },142 },

143];143];

144 144 

145function getHoroscope(sign) {145function getHoroscope(sign: string) {

146 return `${sign}: Next Tuesday you will befriend a baby otter.`;146 return `${sign}: Next Tuesday you will befriend a baby otter.`;

147}147}

148 148 

149// Create a running input list we will add to over time149// Create a running input list we will add to over time

150 150 

151let input = [151let input: OpenAI.Responses.ResponseInput = [

152 { role: "user", content: "What is my horoscope? I am an Aquarius." },152 { role: "user", content: "What is my horoscope? I am an Aquarius." },

153];153];

154 154 


638 638 

639Execute function calls and append results639Execute function calls and append results

640 640 

641```javascript641```typescript

642import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";642import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

643 643 

644input.push(...toResponseInputItems(response.output));644input.push(...toResponseInputItems(response.output));


777 777 

778Execute function calls and append results778Execute function calls and append results

779 779 

780```javascript780```typescript

781const callFunction = async (name, args) => {781const callFunction = async (name: string, args: Record<string, unknown>) => {

782 if (name === "get_weather") {782 if (name === "get_weather") {

783 return getWeather(args.latitude, args.longitude);783 return getWeather(args.latitude, args.longitude);

784 }784 }


906 906 

907Send results back to model907Send results back to model

908 908 

909```javascript909```typescript

910const response = await openai.responses.create({910const response = await openai.responses.create({

911 model: "gpt-6-astra",911 model: "gpt-6-astra",

912 input,912 input,


1209 1209 

1210Streaming function calls1210Streaming function calls

1211 1211 

1212```javascript1212```typescript

1213import { OpenAI } from "openai";1213import { OpenAI } from "openai";

1214 1214 

1215const openai = new OpenAI();1215const openai = new OpenAI();

1216 1216 

1217const tools = [1217const tools: OpenAI.Responses.Tool[] = [

1218 {1218 {

1219 type: "function",1219 type: "function",

1220 name: "get_weather",1220 name: "get_weather",


1421 1421 

1422Accumulating tool_call deltas1422Accumulating tool_call deltas

1423 1423 

1424```javascript1424```typescript

1425const finalToolCalls = {};1425const finalToolCalls: Record<

1426 number,

1427 import("openai").OpenAI.Responses.ResponseFunctionToolCall

1428> = {};

1426 1429 

1427for await (const event of stream) {1430for await (const event of stream) {

1428 if (1431 if (


1641 1644 

1642Custom tool calling example1645Custom tool calling example

1643 1646 

1644```javascript1647```typescript

1645import OpenAI from "openai";1648import OpenAI from "openai";

1646const client = new OpenAI();1649const client = new OpenAI();

1647 1650 


1778 1781 

1779Lark context free grammar example1782Lark context free grammar example

1780 1783 

1781```javascript1784```typescript

1782import OpenAI from "openai";1785import OpenAI from "openai";

1783const client = new OpenAI();1786const client = new OpenAI();

1784 1787 


2073 2076 

2074Regex context free grammar example2077Regex context free grammar example

2075 2078 

2076```javascript2079```typescript

2077import OpenAI from "openai";2080import OpenAI from "openai";

2078const client = new OpenAI();2081const client = new OpenAI();

2079 2082 

Details

62 }'62 }'

63```63```

64 64 

65```javascript65```typescript

66import OpenAI from "openai";66import OpenAI from "openai";

67 67 

68const projectId = "your-project-id";68const projectId = "your-project-id";

Details

129 129 

130 Generate an image130 Generate an image

131 131 

132```javascript132```typescript

133import OpenAI from "openai";133import OpenAI from "openai";

134import fs from "fs";134import fs from "fs";

135const openai = new OpenAI();135const openai = new OpenAI();


145});145});

146 146 

147// Save the image to a file147// Save the image to a file

148const image_base64 = result.data[0].b64_json;148const image_base64 = result.data?.[0]?.b64_json;

149if (!image_base64) throw new Error("Image generation returned no image.");

149const image_bytes = Buffer.from(image_base64, "base64");150const image_bytes = Buffer.from(image_base64, "base64");

150fs.writeFileSync("otter.png", image_bytes);151fs.writeFileSync("otter.png", image_bytes);

151```152```


283 284 

284 Generate an image285 Generate an image

285 286 

286```javascript287```typescript

287import OpenAI from "openai";288import OpenAI from "openai";

288const openai = new OpenAI();289const openai = new OpenAI();

289 290 


301 302 

302if (imageData.length > 0) {303if (imageData.length > 0) {

303 const imageBase64 = imageData[0];304 const imageBase64 = imageData[0];

305 if (!imageBase64) throw new Error("Image generation returned no image.");

304 const fs = await import("fs");306 const fs = await import("fs");

305 fs.writeFileSync("otter.png", Buffer.from(imageBase64, "base64"));307 fs.writeFileSync("otter.png", Buffer.from(imageBase64, "base64"));

306}308}


463 465 

464Force image creation with action466Force image creation with action

465 467 

466```javascript468```typescript

467import OpenAI from "openai";469import OpenAI from "openai";

468const openai = new OpenAI();470const openai = new OpenAI();

469 471 


483 485 

484if (imageData.length > 0) {486if (imageData.length > 0) {

485 const imageBase64 = imageData[0];487 const imageBase64 = imageData[0];

488 if (!imageBase64) throw new Error("Image generation returned no image.");

486 const fs = await import("fs");489 const fs = await import("fs");

487 fs.writeFileSync("otter.png", Buffer.from(imageBase64, "base64"));490 fs.writeFileSync("otter.png", Buffer.from(imageBase64, "base64"));

488}491}


652 655 

653 Multi-turn image generation656 Multi-turn image generation

654 657 

655```javascript658```typescript

656import OpenAI from "openai";659import OpenAI from "openai";

657const openai = new OpenAI();660const openai = new OpenAI();

658 661 


669 672 

670if (imageData.length > 0) {673if (imageData.length > 0) {

671 const imageBase64 = imageData[0];674 const imageBase64 = imageData[0];

675 if (!imageBase64) throw new Error("Image generation returned no image.");

672 const fs = await import("fs");676 const fs = await import("fs");

673 fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));677 fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));

674}678}


688 692 

689if (imageData_fwup.length > 0) {693if (imageData_fwup.length > 0) {

690 const imageBase64 = imageData_fwup[0];694 const imageBase64 = imageData_fwup[0];

695 if (!imageBase64) throw new Error("Image generation returned no image.");

691 const fs = await import("fs");696 const fs = await import("fs");

692 fs.writeFileSync(697 fs.writeFileSync(

693 "cat_and_otter_realistic.png",698 "cat_and_otter_realistic.png",


954 959 

955 Multi-turn image generation960 Multi-turn image generation

956 961 

957```javascript962```typescript

958import OpenAI from "openai";963import OpenAI from "openai";

959const openai = new OpenAI();964const openai = new OpenAI();

960 965 


973 978 

974if (imageData.length > 0) {979if (imageData.length > 0) {

975 const imageBase64 = imageData[0];980 const imageBase64 = imageData[0];

981 if (!imageBase64) throw new Error("Image generation returned no image.");

976 const fs = await import("fs");982 const fs = await import("fs");

977 fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));983 fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));

978}984}


987 content: [{ type: "input_text", text: "Now make it look realistic" }],993 content: [{ type: "input_text", text: "Now make it look realistic" }],

988 },994 },

989 {995 {

990 type: "image_generation_call",996 type: "item_reference",

991 id: imageGenerationCalls[0].id,997 id: imageGenerationCalls[0].id,

992 },998 },

993 ],999 ],


1000 1006 

1001if (imageData_fwup.length > 0) {1007if (imageData_fwup.length > 0) {

1002 const imageBase64 = imageData_fwup[0];1008 const imageBase64 = imageData_fwup[0];

1009 if (!imageBase64) throw new Error("Image generation returned no image.");

1003 const fs = await import("fs");1010 const fs = await import("fs");

1004 fs.writeFileSync(1011 fs.writeFileSync(

1005 "cat_and_otter_realistic.png",1012 "cat_and_otter_realistic.png",


1360 1367 

1361 Stream an image1368 Stream an image

1362 1369 

1363```javascript1370```typescript

1364import OpenAI from "openai";1371import OpenAI from "openai";

1365import fs from "fs";1372import fs from "fs";

1366const openai = new OpenAI();1373const openai = new OpenAI();

1367 1374 

1368function saveBase64Image(filename, imageBase64) {1375function saveBase64Image(filename: string, imageBase64: string | null) {

1376 if (!imageBase64) throw new Error("Image generation returned no image.");

1369 const imageBuffer = Buffer.from(imageBase64, "base64");1377 const imageBuffer = Buffer.from(imageBase64, "base64");

1370 fs.writeFileSync(filename, imageBuffer);1378 fs.writeFileSync(filename, imageBuffer);

1371}1379}


1578 1586 

1579 Stream an image1587 Stream an image

1580 1588 

1581```javascript1589```typescript

1582import fs from "fs";1590import fs from "fs";

1583import OpenAI from "openai";1591import OpenAI from "openai";

1584 1592 


1597 if (event.type === "image_generation.partial_image") {1605 if (event.type === "image_generation.partial_image") {

1598 const idx = event.partial_image_index;1606 const idx = event.partial_image_index;

1599 const imageBase64 = event.b64_json;1607 const imageBase64 = event.b64_json;

1608 if (!imageBase64) throw new Error("Image generation returned no image.");

1600 const imageBuffer = Buffer.from(imageBase64, "base64");1609 const imageBuffer = Buffer.from(imageBase64, "base64");

1601 fs.writeFileSync(`river${idx}.png`, imageBuffer);1610 fs.writeFileSync(`river${idx}.png`, imageBuffer);

1602 }1611 }


1783 1792 

1784Create a File1793Create a File

1785 1794 

1786```javascript1795```typescript

1787import fs from "fs";1796import fs from "fs";

1788import OpenAI from "openai";1797import OpenAI from "openai";

1789 1798 

1790const openai = new OpenAI();1799const openai = new OpenAI();

1791 1800 

1792async function createFile(filePath) {1801async function createFile(filePath: fs.PathLike) {

1793 const fileContent = fs.createReadStream(filePath);1802 const fileContent = fs.createReadStream(filePath);

1794 const result = await openai.files.create({1803 const result = await openai.files.create({

1795 file: fileContent,1804 file: fileContent,


1880 1889 

1881Create a base64 encoded image1890Create a base64 encoded image

1882 1891 

1883```javascript1892```typescript

1884import fs from "fs";1893import fs from "fs";

1885 1894 

1886function encodeImage(filePath) {1895function encodeImage(filePath: fs.PathOrFileDescriptor) {

1887 const base64Image = fs.readFileSync(filePath, "base64");1896 const base64Image = fs.readFileSync(filePath, "base64");

1888 return base64Image;1897 return base64Image;

1889}1898}


1947 1956 

1948Edit an image1957Edit an image

1949 1958 

1950```javascript1959```typescript

1951import fs from "fs";1960import fs from "fs";

1952import OpenAI from "openai";1961import OpenAI from "openai";

1953 1962 

1954const openai = new OpenAI();1963const openai = new OpenAI();

1955 1964 

1956function encodeImage(filePath) {1965function encodeImage(filePath: fs.PathOrFileDescriptor) {

1957 return fs.readFileSync(filePath, "base64");1966 return fs.readFileSync(filePath, "base64");

1958}1967}

1959 1968 

1960async function createFile(filePath) {1969async function createFile(filePath: fs.PathLike) {

1961 const result = await openai.files.create({1970 const result = await openai.files.create({

1962 file: fs.createReadStream(filePath),1971 file: fs.createReadStream(filePath),

1963 purpose: "vision",1972 purpose: "vision",


2013 2022 

2014if (imageData.length > 0) {2023if (imageData.length > 0) {

2015 const imageBase64 = imageData[0];2024 const imageBase64 = imageData[0];

2025 if (!imageBase64) throw new Error("Image generation returned no image.");

2016 fs.writeFileSync("gift-basket.png", Buffer.from(imageBase64, "base64"));2026 fs.writeFileSync("gift-basket.png", Buffer.from(imageBase64, "base64"));

2017} else {2027} else {

2018 console.log(response.output_text);2028 console.log(response.output_text);


2321 2331 

2322 Edit an image2332 Edit an image

2323 2333 

2324```javascript2334```typescript

2325import fs from "fs";2335import fs from "fs";

2326import OpenAI, { toFile } from "openai";2336import OpenAI, { toFile } from "openai";

2327 2337 


2356});2366});

2357 2367 

2358// Save the image to a file2368// Save the image to a file

2359const image_base64 = response.data[0].b64_json;2369const image_base64 = response.data?.[0]?.b64_json;

2370if (!image_base64) throw new Error("Image generation returned no image.");

2360const image_bytes = Buffer.from(image_base64, "base64");2371const image_bytes = Buffer.from(image_base64, "base64");

2361fs.writeFileSync("basket.png", image_bytes);2372fs.writeFileSync("basket.png", image_bytes);

2362```2373```


2686 2697 

2687 Edit an image with a mask2698 Edit an image with a mask

2688 2699 

2689```javascript2700```typescript

2690import fs from "fs";2701import fs from "fs";

2691import OpenAI from "openai";2702import OpenAI from "openai";

2692 2703 

2693const openai = new OpenAI();2704const openai = new OpenAI();

2694 2705 

2695async function createFile(filePath) {2706async function createFile(filePath: fs.PathLike) {

2696 const result = await openai.files.create({2707 const result = await openai.files.create({

2697 file: fs.createReadStream(filePath),2708 file: fs.createReadStream(filePath),

2698 purpose: "vision",2709 purpose: "vision",


2739 2750 

2740if (imageData.length > 0) {2751if (imageData.length > 0) {

2741 const imageBase64 = imageData[0];2752 const imageBase64 = imageData[0];

2753 if (!imageBase64) throw new Error("Image generation returned no image.");

2742 fs.writeFileSync("lounge.png", Buffer.from(imageBase64, "base64"));2754 fs.writeFileSync("lounge.png", Buffer.from(imageBase64, "base64"));

2743}2755}

2744```2756```


2992 3004 

2993 Edit an image with a mask3005 Edit an image with a mask

2994 3006 

2995```javascript3007```typescript

2996import fs from "fs";3008import fs from "fs";

2997import OpenAI, { toFile } from "openai";3009import OpenAI, { toFile } from "openai";

2998 3010 


3010});3022});

3011 3023 

3012// Save the image to a file3024// Save the image to a file

3013const image_base64 = rsp.data[0].b64_json;3025const image_base64 = rsp.data?.[0]?.b64_json;

3026if (!image_base64) throw new Error("Image generation returned no image.");

3014const image_bytes = Buffer.from(image_base64, "base64");3027const image_bytes = Buffer.from(image_base64, "base64");

3015fs.writeFileSync("lounge.png", image_bytes);3028fs.writeFileSync("lounge.png", image_bytes);

3016```3029```


3405 3418 

3406Handle moderation-blocked image generation errors3419Handle moderation-blocked image generation errors

3407 3420 

3408```javascript3421```typescript

3409import OpenAI from "openai";3422import OpenAI from "openai";

3410 3423 

3411const openai = new OpenAI();3424const openai = new OpenAI();


3418 prompt: "Create a poster humiliating my coworker with insulting captions",3431 prompt: "Create a poster humiliating my coworker with insulting captions",

3419 });3432 });

3420} catch (error) {3433} catch (error) {

3421 if (error?.code !== "moderation_blocked") {3434 if (

3435 !(error instanceof OpenAI.APIError) ||

3436 error.code !== "moderation_blocked"

3437 ) {

3422 throw error;3438 throw error;

3423 }3439 }

3424 3440 

3425 const moderationDetails = error.error?.moderation_details;3441 const moderationDetails =

3442 error.error && "moderation_details" in error.error

3443 ? (error.error.moderation_details as {

3444 categories?: string[];

3445 moderation_stage?: string;

3446 })

3447 : undefined;

3426 const categories = moderationDetails?.categories ?? [];3448 const categories = moderationDetails?.categories ?? [];

3427 const stage = moderationDetails?.moderation_stage;3449 const stage = moderationDetails?.moderation_stage;

3428 3450 

Details

33 33 

34Generate images with Responses34Generate images with Responses

35 35 

36```javascript36```typescript

37import OpenAI from "openai";37import OpenAI from "openai";

38const openai = new OpenAI();38const openai = new OpenAI();

39 39 


51 51 

52if (imageData.length > 0) {52if (imageData.length > 0) {

53 const imageBase64 = imageData[0];53 const imageBase64 = imageData[0];

54 if (!imageBase64) throw new Error("The image generation result is empty.");

54 const fs = await import("fs");55 const fs = await import("fs");

55 fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));56 fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));

56}57}


252 253 

253 Analyze the content of an image254 Analyze the content of an image

254 255 

255```javascript256```typescript

256import OpenAI from "openai";257import OpenAI from "openai";

257 258 

258const openai = new OpenAI();259const openai = new OpenAI();


474 475 

475 Analyze the content of an image476 Analyze the content of an image

476 477 

477```javascript478```typescript

478import fs from "fs";479import fs from "fs";

479import OpenAI from "openai";480import OpenAI from "openai";

480 481 


719 720 

720 Analyze the content of an image721 Analyze the content of an image

721 722 

722```javascript723```typescript

723import OpenAI from "openai";724import OpenAI from "openai";

724import fs from "fs";725import fs from "fs";

725 726 

726const openai = new OpenAI();727const openai = new OpenAI();

727 728 

728// Function to create a file with the Files API729// Function to create a file with the Files API

729async function createFile(filePath) {730async function createFile(filePath: fs.PathLike) {

730 const fileContent = fs.createReadStream(filePath);731 const fileContent = fs.createReadStream(filePath);

731 const result = await openai.files.create({732 const result = await openai.files.create({

732 file: fileContent,733 file: fileContent,

Details

2 2 

3> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.3> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.

4 4 

5This guide covers the core set of principles you can apply to improve latency across a wide variety of LLM-related use cases. These techniques come from working with a wide range of customers and developers on production applications, so they should apply regardless of what you're building—from a granular workflow to an end-to-end chat application.5Measure where users wait before changing the model or prompt.

6 6 

7Although there are many individual techniques, this guide groups them into **seven principles** that represent a high-level taxonomy of approaches for improving latency.7- **Time to first token (TTFT)** measures how long an API request takes to start returning content. For streaming text in the Responses API, time the request from when you send it until you receive the first nonempty `response.output_text.delta`.

8- **End-to-end latency** measures how long the user waits for the complete result. Time it from the user's action through retrieval, model and tool calls, retries, and rendering.

8 9 

9At the end, we'll walk through an [example](#example) to see how they can be applied.10Compare the median (p50) and the 95th percentile (p95) on representative traffic. Group similar requests by model, service tier, and task. Record input, cached input, and output tokens alongside the timings. If TTFT looks good but users still see a blank screen, time the work before the model call and check when the client displays the first text.

10 11 

11### Seven principles12### Seven principles

12 13 


20 21 

21## Process tokens faster22## Process tokens faster

22 23 

23**Inference speed** is probably the first thing that comes to mind when addressing latency (but as you'll see soon, it's far from the only one). This refers to the actual **rate at which the LLM processes tokens**, and is often measured in TPM (tokens per minute) or TPS (tokens per second).24Choose a model using examples from your workload. For a focused task like routing a support ticket, try [`gpt-6-luna`](https://developers.openai.com/api/docs/models/gpt-6-luna). For more demanding work, use the [model selection guide](https://developers.openai.com/api/docs/guides/model-selection) to choose a comparison model. Keep the fastest configuration that meets your quality target, including on difficult cases.

24 25 

25The main factor that influences inference speed is **model size**—smaller models usually run faster (and cheaper), and when used correctly can even outperform larger models. To maintain high-quality performance with smaller models, you can explore:26If you need to keep the same model, compare Standard processing with [Fast mode](https://developers.openai.com/api/docs/guides/fast-mode) or [Ultrafast mode](https://developers.openai.com/api/docs/guides/ultrafast-mode) where supported. Both charge a premium. Compare the same prompts and output lengths, and record the `service_tier` returned in each response.

26 

27- using a longer, [more detailed prompt](https://developers.openai.com/api/docs/guides/prompt-engineering#prompt-engineering),

28- adding (more) [few-shot examples](https://developers.openai.com/api/docs/guides/prompt-engineering#few-shot-learning), or

29- [fine-tuning](https://developers.openai.com/api/docs/guides/model-optimization) / distillation.

30 

31You can also employ inference optimizations like our [**Predicted outputs**](https://developers.openai.com/api/docs/guides/predicted-outputs) feature. Predicted outputs let you significantly reduce latency of a generation when you know most of the output ahead of time, such as code editing tasks. By giving the model a prediction, the LLM can focus more on the actual changes, and less on the content that will remain the same.

32 

33 

34 

35Other factors that affect inference speed are the amount of

36 **compute** you have available and any additional

37 **inference optimizations** you employ.

38

39 

40 Most people can't influence these factors directly, but if you're curious, and

41 have some control over your infra, **faster hardware** or

42 **running engines at a lower saturation** may give you a modest

43 TPM boost. And if you're down in the trenches, there's a myriad of other

44 [inference optimizations](https://lilianweng.github.io/posts/2023-01-10-inference-optimization/)

45 that are a bit beyond the scope of this guide.

46 27 

28For long answers, measure visible output speed in tokens per second. Count the text tokens received after the first text event and divide by the time from the first text event to the last. A streamed event can contain multiple tokens. A tokens-per-minute rate limit measures how much traffic you can send across requests.

47 29 

30For Chat Completions on a supported model, [Predicted Outputs](https://developers.openai.com/api/docs/guides/predicted-outputs) can reduce generation time when you already know most of the answer, such as when editing a few lines in a file. Check model and parameter compatibility before using this option.

48 31 

49## Generate fewer tokens32## Generate fewer tokens

50 33 

51Generating tokens is almost always the highest latency step when using an LLM: as a general heuristic, **cutting 50% of your output tokens may cut ~50% of your latency**. The way you reduce your output size will depend on output type:34If an answer starts quickly but takes too long to finish, inspect what the model generates.

52 

53If you're generating **natural language**, **asking the model to be more concise** ("under 20 words" or "be brief") may help. You can also use few-shot examples and/or fine-tuning to teach the model shorter responses.

54 

55If you're generating **structured output**, try to **minimize your output syntax** where possible: shorten function names, omit named arguments, coalesce parameters, etc.

56 35 

57Finally, while not common, you can also use `max_tokens` or `stop_tokens` to end your generation early.36- **Visible text.** Ask for the amount of detail the user needs, such as “Give the next step in one sentence.” On supported Responses API models, lower [`text.verbosity`](https://developers.openai.com/api/docs/guides/deployment-checklist#set-up-textverbosity) for shorter answers.

37- **Reasoning.** For routine extraction or classification, try a lower supported [`reasoning.effort`](https://developers.openai.com/api/docs/guides/reasoning#reasoning-effort). Compare accuracy and time to first text on the same examples. Check `usage.output_tokens_details.reasoning_tokens` to see how much reasoning the model used.

38- **Structured output.** Request only the fields your application consumes. Compute values you already know, such as a message count, in application code. Use [Structured Outputs](https://developers.openai.com/api/docs/guides/structured-outputs) when the response must follow a schema.

58 39 

59Always remember: an output token cut is a (milli)second earned!40In the Responses API, `max_output_tokens` caps both reasoning and visible output tokens. A low cap can leave the response `incomplete`, even before it produces visible text. Use the cap as a budget and check response status before consuming a partial answer.

60 41 

61## Use fewer input tokens42## Use fewer input tokens

62 43 

63While reducing the number of input tokens does result in lower latency, this is not usually a significant factor—**cutting 50% of your prompt may only result in a 1–5% latency improvement**. Unless you're working with truly massive context sizes (documents, images), you may want to spend your efforts elsewhere.44A long prompt can delay the first token, especially when much of the input is new. Filter search results for relevance, strip markup you don't need, and send only the context required to answer accurately.

64 45 

65That being said, if you _are_ working with massive contexts (or you're set on squeezing every last bit of performance _and_ you've exhausted all other options) you can use the following techniques to reduce your input tokens:46For repeated inputs, put stable instructions, examples, and tool definitions first. In multi-turn conversations, [keep the prefix unchanged](https://developers.openai.com/api/docs/guides/preserved-reasoning) and append new messages and tool results. [Prompt caching](https://developers.openai.com/api/docs/guides/prompt-caching) can reuse an eligible exact prefix match. In the Responses API, inspect `usage.input_tokens_details.cached_tokens` and compare TTFT for requests with and without cache hits.

66 

67- **Fine-tuning the model**, to replace the need for lengthy instructions / examples.

68- **Filtering context input**, like pruning RAG results, cleaning HTML, etc.

69- **Maximize shared prompt prefix**, by putting dynamic portions (for example, RAG results and history) later in the prompt. This makes your request more [KV cache](https://medium.com/@joaolages/kv-caching-explained-276520203249)-friendly (which most LLM providers use) and means fewer input tokens are processed on each request.

70 

71Check out our docs to learn more about how [prompt

72 caching](https://developers.openai.com/api/docs/guides/prompt-engineering#save-on-cost-and-latency-with-prompt-caching)

73 works.

74 47 

75## Make fewer requests48## Make fewer requests

76 49 

77Each time you make a request, you incur some round-trip latency—this can start to add up.50Each sequential model or tool call adds another wait. Combine steps when one request has all the information it needs. For example, a model can turn a customer's follow-up into a standalone search query and decide whether a lookup is necessary in the same response. A reply that depends on a lookup still needs its result.

78 

79If you have sequential steps for the LLM to perform, instead of firing off one request per step consider **putting them in a single prompt and getting them all in a single response**. You'll avoid the additional round-trip latency, and potentially also reduce complexity of processing multiple responses.

80 51 

81An approach to doing this is by collecting your steps in an enumerated list in the combined prompt, and then requesting the model to return the results in named fields in a JSON object. This way, you can parse and reference each result.52If your agent makes many short, sequential tool calls, try [WebSocket mode](https://developers.openai.com/api/docs/guides/websocket-mode). Reuse the connection and continue from the prior response with `previous_response_id`, sending only new input items and tool results. This reduces overhead between turns.

82 53 

83## Parallelize54## Parallelize

84 55 

85Parallel processing can be powerful when performing multiple steps with an LLM.56Run independent work concurrently. For example, once you have an order ID, you can look up its shipment status while fetching the return policy. An answer that needs both can start as soon as the slower lookup finishes. On supported models, [async tool calling](https://developers.openai.com/api/docs/guides/async-tool-calling) also lets the model continue independent work while your application runs a tool.

86 57 

87If the steps **are _not_ strictly sequential**, you can **split them out into parallel calls**. Two shirts take just as long to dry as one.58For a likely but uncertain branch, consider starting a read-only lookup early and discarding it if it's unnecessary. Measure the extra cost on a wrong guess. Wait for required checks before displaying a result or taking an action such as issuing a refund.

88 

89If the steps **_are_ strictly sequential**, however, you might still be able to **leverage speculative execution**. This is particularly effective for classification steps where one outcome is more likely than the others (for example, moderation).

90 

911. Start step 1 and step 2 simultaneously (for example, input moderation and story generation)

922. Verify the result of step 1

933. If result was not the expected, cancel step 2 (and retry if necessary)

94 

95If your guess for step 1 is right, then you essentially got to run it with zero added latency!

96 59 

97## Make your users wait less60## Make your users wait less

98 61 

99There's a huge difference between **waiting** and **watching progress happen**—make sure your users experience the latter. Here are a few techniques:62For interactive text over HTTP, [stream the response](https://developers.openai.com/api/docs/guides/streaming-responses) with `stream: true` and display text as it arrives. Streaming lets the user start reading before generation finishes. Time to the first visible text still depends on the request, including any reasoning or tool work before the answer.

100 63 

101- **Streaming**: The single most effective approach, as it cuts the _waiting_ time to a second or less. (ChatGPT would feel pretty different if you saw nothing until each response was done.)64If you check or moderate output before displaying it, buffer enough text to perform that check. For longer tasks, show actual progress, such as “Looking up your order,” while the lookup runs. When the user can return later, [Background mode](https://developers.openai.com/api/docs/guides/background) lets your application submit the work and retrieve the result asynchronously.

102- **Chunking**: If your output needs further processing before being shown to the user (moderation, translation), consider **processing it in chunks** instead of all at once. Do this by streaming to your back end, then sending processed chunks to your front end.

103- **Show your steps**: If you're taking multiple steps or using tools, surface this to the user. The more real progress you can show, the better.

104- **Loading states**: Spinners and progress bars go a long way.

105 

106Note that while **showing your steps & having loading states** have a mostly

107psychological effect, **streaming & chunking** genuinely do reduce overall

108latency once you consider the app + user system: the user will finish reading a response

109sooner.

110 65 

111## Don't default to an LLM66## Don't default to an LLM

112 67 

113Language models are powerful and versatile, and are therefore sometimes used in cases where a **faster classical method** would be more appropriate. Identifying such cases may allow you to cut your latency significantly. Consider the following examples:68Use application code when you already know the answer. Render an order status from the order API, use a template to confirm a refund that succeeded, or show search results directly. Each of these can remove a model call from the user's wait.

114 

115- **Hard-coding:** If your **output** is highly constrained, you may not need an LLM to generate it. Action confirmations, refusal messages, and requests for standard input are all great candidates to be hard-coded. (You can even use the age-old method of coming up with a few variations for each.)

116- **Pre-computing:** If your **input** is constrained (for example, category selection), you can generate multiple responses in advance, and just make sure you never show the same one to a user twice.

117- **Leveraging UI:** Summarized metrics, reports, or search results are sometimes better conveyed with classical, bespoke UI components rather than LLM-generated text.

118- **Traditional optimization techniques:** An LLM application is still an application; binary search, caching, hash maps, and runtime complexity are all _still_ useful in a world of language models.

119 69 

120## Example70## Example

121 71 

122Let's now look at a sample application, identify potential latency optimizations, and propose some solutions!

123 

124We'll be analyzing the architecture and prompts of a hypothetical customer service bot inspired by real production applications. The [architecture and prompts](#architecture-and-prompts) section sets the stage, and the [analysis and optimizations](#analysis-and-optimizations) section will walk through the latency optimization process.

125 

126You'll notice this example doesn't cover every single principle, much like

127 real-world use cases don't require applying every technique.

128 

129### Architecture and prompts72### Architecture and prompts

130 73 

131The following is the **initial architecture** for a hypothetical **customer service bot**. This is what we'll be making changes to.74A customer asks, “Is it still eligible for a return?” after discussing a pair of headphones. The support assistant makes three model calls in sequence. The first rewrites the question with the product name. The second decides whether to search. After retrieval, the third generates a reply plus internal fields for message count, sentiment, and tone. The customer sees nothing until the final call finishes.

132 

133![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-0.png)

134 

135At a high level, the diagram flow describes the following process:

136 

1371. A user sends a message as part of an ongoing conversation.

1382. The last message is turned into a **self-contained query** (see examples in prompt).

1393. We determine whether or not **additional (retrieved) information is required** to respond to that query.

1404. **Retrieval** is performed, producing search results.

1415. The assistant **reasons** about the user's query and search results, and **produces a response**.

1426. The response is sent back to the user.

143 

144Below are the prompts used in each part of the diagram. While they are still only hypothetical and simplified, they are written with the same structure and wording that you would find in a production application.

145 

146Places where you see placeholders like "**[user input here]**" represent

147 dynamic portions, that would be replaced by actual data at runtime.

148 

149 

150 

151#### Query contextualization prompt

152 

153 

154 

155Re-writes user query to be a self-contained search query.

156 

157```example-chat

158SYSTEM: Given the previous conversation, re-write the last user query so it contains

159all necessary context.

160 

161# Example

162History: [{user: "What is your return policy?"},{assistant: "..."}]

163User Query: "How long does it cover?"

164Response: "How long does the return policy cover?"

165 

166# Conversation

167[last 3 messages of conversation]

168 

169# User Query

170[last user query]

171 

172USER: [JSON-formatted input conversation here]

173```

174 

175 

176 

177 

178 

179 

180 

181#### Retrieval check prompt

182 

183 

184Determines whether a query requires performing retrieval to respond.

185 

186```example-chat

187SYSTEM: Given a user query, determine whether it requires doing a realtime lookup to

188respond to.

189 

190# Examples

191User Query: "How can I return this item after 30 days?"

192Response: "true"

193 

194User Query: "Thank you!"

195Response: "false"

196 

197USER: [input user query here]

198```

199 

200 

201 

202 

203 

204 

205 

206#### Assistant prompt

207 

208 

209Fills the fields of a JSON to reason through a pre-defined set of steps to produce a final response given a user conversation and relevant retrieved information.

210 

211```example-chat

212SYSTEM: You are a helpful customer service bot.

213 

214Use the result JSON to reason about each user query - use the retrieved context.

215 

216# Example

217 

218User: "My computer screen is cracked! I want it fixed now!!!"

219 

220Assistant Response:

221{

222 "message_is_conversation_continuation": "True",

223 "number_of_messages_in_conversation_so_far": "1",

224 "user_sentiment": "Aggravated",

225 "query_type": "Hardware Issue",

226 "response_tone": "Validating and solution-oriented",

227 "response_requirements": "Propose options for repair or replacement.",

228 "user_requesting_to_talk_to_human": "False",

229 "enough_information_in_context": "True",

230 "response": "..."

231}

232 

233USER: # Relevant Information

234` ` `

235[retrieved context]

236` ` `

237 

238USER: [input user query here]

239```

240 

241 

242 

243 

244 75 

245### Analysis and optimizations76### Analysis and optimizations

246 77 

247#### Part 1: Looking at retrieval prompts78| Step | Change | What to measure |

248 79| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |

249Looking at the architecture, the first thing that stands out is the **consecutive GPT-4 calls** - these hint at a potential inefficiency, and can often be replaced by a single call or parallel calls.80| Route the question | Ask one model to decide whether to search and, if so, produce the standalone query. For this turn, the query is “headphones return policy.” An acknowledgment can skip retrieval. | Routing accuracy on both kinds of turns and time until retrieval starts. |

250 81| Fetch the evidence | Once the router identifies a return question, fetch the policy and the customer's order details concurrently if both inputs are available. | Elapsed time until both results are ready. |

251![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-2.png)82| Answer | Give the model the policy and order details, request only the customer-facing reply, and stream the text. If the policy or order lacks a fact needed to decide eligibility, ask for it. | Time to first visible text, time to the complete reply, and whether the eligibility decision is correct. |

252 

253In this case, since the check for retrieval requires the contextualized query, let's **combine them into a single prompt** to [make fewer requests](#make-fewer-requests).

254 

255![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-3.png)

256 

257 

258 

259##### Combined query contextualization and retrieval check prompt

260 

261 

262 

263**What changed?** Before, we had one prompt to re-write the query and one to determine whether this requires doing a retrieval lookup. Now, this combined prompt does both. Specifically, notice the updated instruction in the first line of the prompt, and the updated output JSON:

264 

265```javascript

266{

267 query: "[contextualized query]",

268 retrieval: "[true/false - whether retrieval is required]",

269};

270```

271 

272```ruby

273require "json"

274 

275combined_query = {

276 query: "[contextualized query]",

277 retrieval: "[true/false - whether retrieval is required]"

278}

279 

280puts(JSON.generate(combined_query))

281```

282 

283 

284```example-chat

285SYSTEM: Given the previous conversation, re-write the last user query so it contains

286all necessary context. Then, determine whether the full request requires doing a

287realtime lookup to respond to.

288 

289Respond in the following form:

290{

291 query:"[contextualized query]",

292 retrieval:"[true/false - whether retrieval is required]"

293}

294 

295# Examples

296 

297History: [{user: "What is your return policy?"},{assistant: "..."}]

298User Query: "How long does it cover?"

299Response: {query: "How long does the return policy cover?", retrieval: "true"}

300 

301History: [{user: "How can I return this item after 30 days?"},{assistant: "..."}]

302User Query: "Thank you!"

303Response: {query: "Thank you!", retrieval: "false"}

304 

305# Conversation

306[last 3 messages of conversation]

307 

308# User Query

309[last user query]

310 

311USER: [JSON-formatted input conversation here]

312```

313 

314 

315 

316 

317 

318 

319 

320Actually, adding context and determining whether to retrieve are straightforward and well-defined tasks, so we can likely use a **smaller, fine-tuned model** instead. Switching to GPT-3.5 will let us [process tokens faster](#process-tokens-faster).

321 

322![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-4.png)

323 

324#### Part 2: Analyzing the assistant prompt

325 

326Let's now direct our attention to the Assistant prompt. There seem to be many distinct steps happening as it fills the JSON fields—this could indicate an opportunity to [parallelize](#parallelize).

327 

328![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-5.png)

329 

330However, let's pretend we have run some tests and discovered that splitting the reasoning steps in the JSON produces worse responses, so we need to explore different solutions.

331 

332**Could we use a fine-tuned GPT-3.5 instead of GPT-4?** Maybe—but in general, open-ended responses from assistants are best left to GPT-4 so it can better handle a greater range of cases. That being said, looking at the reasoning steps themselves, they may not all require GPT-4-level reasoning to produce. Their well-defined, limited scope makes them **good potential candidates for fine-tuning**.

333 

334```javascript

335{

336 message_is_conversation_continuation: "True", // <-

337 number_of_messages_in_conversation_so_far: "1", // <-

338 user_sentiment: "Aggravated", // <-

339 query_type: "Hardware Issue", // <-

340 response_tone: "Validating and solution-oriented", // <-

341 response_requirements: "Propose options for repair or replacement.", // <-

342 user_requesting_to_talk_to_human: "False", // <-

343 enough_information_in_context: "True", // <-

344 response: "...", // X -- benefits from GPT-4

345};

346```

347 

348```ruby

349require "json"

350 

351assistant_response = {

352 message_is_conversation_continuation: "True", # <-

353 number_of_messages_in_conversation_so_far: "1", # <-

354 user_sentiment: "Aggravated", # <-

355 query_type: "Hardware Issue", # <-

356 response_tone: "Validating and solution-oriented", # <-

357 response_requirements: "Propose options for repair or replacement.", # <-

358 user_requesting_to_talk_to_human: "False", # <-

359 enough_information_in_context: "True", # <-

360 response: "..." # X -- benefits from GPT-4

361}

362 

363puts(JSON.generate(assistant_response))

364```

365 

366 

367This opens up the possibility of a trade-off. Do we keep this as a **single request entirely generated by GPT-4**, or **split it into two sequential requests** and use GPT-3.5 for all but the final response? We have a case of conflicting principles: the first option lets us [make fewer requests](#make-fewer-requests), but the second may let us [process tokens faster](#process-tokens-faster).

368 

369As with many optimization tradeoffs, the answer will depend on the details. For example:

370 

371- The proportion of tokens in the `response` vs the other fields.

372- The average latency decrease from processing most fields faster.

373- The average latency _increase_ from doing two requests instead of one.

374 

375The conclusion will vary by case, and the best way to make the determination is by testing this with production examples. In this case, let's pretend the tests indicated it's favorable to split the prompt in two to [process tokens faster](#process-tokens-faster).

376 

377![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-6.png)

378 

379**Note:** We'll be grouping `response` and `enough_information_in_context` together in the second prompt to avoid passing the retrieved context to both new prompts.

380 

381 

382 

383##### Assistants prompt - reasoning

384 

385 

386 

387This prompt will be passed to GPT-3.5 and can be fine-tuned on curated examples.

388 

389**What changed?** The "enough_information_in_context" and "response" fields were removed, and the retrieval results are no longer loaded into this prompt.

390 

391```example-chat

392SYSTEM: You are a helpful customer service bot.

393 

394Based on the previous conversation, respond in a JSON to determine the required

395fields.

396 

397# Example

398 

399User: "My freaking computer screen is cracked!"

400 

401Assistant Response:

402{

403 "message_is_conversation_continuation": "True",

404 "number_of_messages_in_conversation_so_far": "1",

405 "user_sentiment": "Aggravated",

406 "query_type": "Hardware Issue",

407 "response_tone": "Validating and solution-oriented",

408 "response_requirements": "Propose options for repair or replacement.",

409 "user_requesting_to_talk_to_human": "False",

410}

411```

412 

413 

414 

415 

416 

417 

418##### Assistants prompt - response

419 

420 

421 

422This prompt will be processed by GPT-4 and will receive the reasoning steps determined in the prior prompt, as well as the results from retrieval.

423 

424**What changed?** All steps were removed except for "enough_information_in_context" and "response". Additionally, the JSON we were previously filling in as output will be passed in to this prompt.

425 

426```example-chat

427SYSTEM: You are a helpful customer service bot.

428 

429Use the retrieved context, as well as these pre-classified fields, to respond to

430the user's query.

431 

432# Reasoning Fields

433` ` `

434[reasoning json determined in previous GPT-3.5 call]

435` ` `

436 

437# Example

438 

439User: "My freaking computer screen is cracked!"

440 

441Assistant Response:

442{

443 "enough_information_in_context": "True",

444 "response": "..."

445}

446 

447USER: # Relevant Information

448` ` `

449[retrieved context]

450` ` `

451```

452 

453 

454 

455 

456 

457 

458 

459 

460In fact, now that the reasoning prompt does not depend on the retrieved context we can [parallelize](#parallelize) and fire it off at the same time as the retrieval prompts.

461 

462![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-6b.png)

463 

464#### Part 3: Optimizing the structured output

465 

466Let's take another look at the reasoning prompt.

467 

468![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-7b.png)

469 

470Taking a closer look at the reasoning JSON you may notice the field names themselves are quite long.

471 

472```javascript

473{

474 message_is_conversation_continuation: "True", // <-

475 number_of_messages_in_conversation_so_far: "1", // <-

476 user_sentiment: "Aggravated", // <-

477 query_type: "Hardware Issue", // <-

478 response_tone: "Validating and solution-oriented", // <-

479 response_requirements: "Propose options for repair or replacement.", // <-

480 user_requesting_to_talk_to_human: "False", // <-

481};

482```

483 

484```ruby

485require "json"

486 

487reasoning = {

488 message_is_conversation_continuation: "True", # <-

489 number_of_messages_in_conversation_so_far: "1", # <-

490 user_sentiment: "Aggravated", # <-

491 query_type: "Hardware Issue", # <-

492 response_tone: "Validating and solution-oriented", # <-

493 response_requirements: "Propose options for repair or replacement.", # <-

494 user_requesting_to_talk_to_human: "False" # <-

495}

496 

497puts(JSON.generate(reasoning))

498```

499 

500 

501By making them shorter and moving explanations to the comments we can [generate fewer tokens](#generate-fewer-tokens).

502 

503```javascript

504{

505 cont: "True", // whether last message is a continuation

506 n_msg: "1", // number of messages in the continued conversation

507 tone_in: "Aggravated", // sentiment of user query

508 type: "Hardware Issue", // type of the user query

509 tone_out: "Validating and solution-oriented", // desired tone for response

510 reqs: "Propose options for repair or replacement.", // response requirements

511 human: "False", // whether user is expressing want to talk to human

512};

513```

514 

515```ruby

516require "json"

517 

518reasoning = {

519 cont: "True", # whether last message is a continuation

520 n_msg: "1", # number of messages in the continued conversation

521 tone_in: "Aggravated", # sentiment of user query

522 type: "Hardware Issue", # type of the user query

523 tone_out: "Validating and solution-oriented", # desired tone for response

524 reqs: "Propose options for repair or replacement.", # response requirements

525 human: "False" # whether user wants to talk to a human

526}

527 

528puts(JSON.generate(reasoning))

529```

530 

531 

532![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-8b.png)

533 

534This small change removed 19 output tokens. While with GPT-3.5 this may only result in a few millisecond improvement, with GPT-4 this could shave off up to a second.

535 

536![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/token-counts-latency-customer-service-large.png)

537 

538You might imagine, however, how this can have quite a significant impact for larger model outputs.

539 

540We could go further and use single characters for the JSON fields, or put everything in an array, but this may start to hurt our response quality. The best way to know, once again, is through testing.

541 

542#### Example wrap-up

543 

544Let's review the optimizations we implemented for the customer service bot example:

545 

546![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-11b.png)

547 83 

5481. **Combined** query contextualization and retrieval check steps to [make fewer requests](#make-fewer-requests).84On the return-question path, this removes one of three sequential model calls and overlaps two independent lookups. Replay the same support conversations before and after each change. Include ambiguous follow-ups and cases that need no lookup so a faster answer still sends customers to the right place.

5492. For the new prompt, **switched to a smaller, fine-tuned GPT-3.5** to [process tokens faster](#process-tokens-faster).

5503. Split the assistant prompt in two, **switching to a smaller, fine-tuned GPT-3.5** for the reasoning, again to [process tokens faster](#process-tokens-faster).

5514. [Parallelized](#parallelize) the retrieval checks and the reasoning steps.

5525. **Shortened reasoning field names** and moved comments into the prompt, to [generate fewer tokens](#generate-fewer-tokens).

Details

37## Limitations37## Limitations

38 38 

39- GPT-6 Astra and GPT-6.1 Sol do not support the `none` reasoning effort; GPT-6.1 Terra, GPT-6 Sol, and GPT-6 Luna do.39- GPT-6 Astra and GPT-6.1 Sol do not support the `none` reasoning effort; GPT-6.1 Terra, GPT-6 Sol, and GPT-6 Luna do.

40- Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna, but not GPT-6 Astra or GPT-6 Sol. [Ultrafast mode](https://developers.openai.com/api/docs/guides/ultrafast-mode) for GPT-6.1 Sol supports US and EU data residency and global processing. GPT-6 Astra Ultrafast supports US data residency and global processing only. See [data residency eligibility](https://developers.openai.com/api/docs/guides/your-data#which-models-and-features-are-eligible-for-data-residency).40- Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna, but not GPT-6 Astra or GPT-6 Sol. [Ultrafast mode](https://developers.openai.com/api/docs/guides/ultrafast-mode) for GPT-6.1 Sol supports US and EU data residency and global processing. GPT-6 Astra Ultrafast supports US data residency and global processing only. See [data residency eligibility](https://developers.openai.com/api/docs/guides/data-residency#which-models-and-features-are-eligible-for-data-residency).

41 41 

42<a id="prompting-best-practices" className="scroll-mt-[110px]"></a>42<a id="prompting-best-practices" className="scroll-mt-[110px]"></a>

43 43 

Details

77 77 

78Include prior text messages in `session.input` when you create the session. For example, add this `input` field to your [session creation configuration](https://developers.openai.com/api/docs/guides/live#connect-your-first-session):78Include prior text messages in `session.input` when you create the session. For example, add this `input` field to your [session creation configuration](https://developers.openai.com/api/docs/guides/live#connect-your-first-session):

79 79 

80```javascript80```typescript

81export const session = {81export const session = {

82 model: "gpt-live-1",82 model: "gpt-live-1",

83 input: [83 input: [


214 214 

215Each event takes plain-string `content` of up to 500 tokens and a required `delegation_id`. Use `null` for session-wide context. For example, send this after your application has verified the user's acceptance and started the lookup:215Each event takes plain-string `content` of up to 500 tokens and a required `delegation_id`. Use `null` for session-wide context. For example, send this after your application has verified the user's acceptance and started the lookup:

216 216 

217```javascript217```typescript

218export function sendUpdate(connection) {218import type { ClientEvent } from "openai/resources/live/live";

219 

220export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

219 connection.send({221 connection.send({

220 type: "session.thinking.append",222 type: "session.thinking.append",

221 event_id: "context_1",223 event_id: "context_1",


353 355 

354Send `session.input_audio.mute` to mute input without ending the session:356Send `session.input_audio.mute` to mute input without ending the session:

355 357 

356```javascript358```typescript

357export function sendUpdate(connection) {359import type { ClientEvent } from "openai/resources/live/live";

360 

361export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

358 connection.send({362 connection.send({

359 type: "session.input_audio.mute",363 type: "session.input_audio.mute",

360 event_id: "mute_1",364 event_id: "mute_1",


441 445 

442Use `session.instructions.append` to request specific spoken wording for a disclosure. `session.commentary.append` may paraphrase the text. After `session.started`, for example, send:446Use `session.instructions.append` to request specific spoken wording for a disclosure. `session.commentary.append` may paraphrase the text. After `session.started`, for example, send:

443 447 

444```javascript448```typescript

445export function sendUpdate(connection) {449import type { ClientEvent } from "openai/resources/live/live";

450 

451export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

446 connection.send({452 connection.send({

447 type: "session.instructions.append",453 type: "session.instructions.append",

448 event_id: "disclosure_1",454 event_id: "disclosure_1",


563 569 

564Stored recordings are available for 30 days. With Zero Data Retention (ZDR), `store` is treated as `false` and forking is unavailable. For fork-based evaluations, use a non-ZDR organization with storage enabled for the project.570Stored recordings are available for 30 days. With Zero Data Retention (ZDR), `store` is treated as `false` and forking is unavailable. For fork-based evaluations, use a non-ZDR organization with storage enabled for the project.

565 571 

566If you have no completed stored recording, [start a new session with relevant saved text history](https://developers.openai.com/api/docs/guides/live-conversations#seed-a-session-with-prior-conversation). See [GPT-Live data controls](https://developers.openai.com/api/docs/guides/your-data#v1livesessions) for storage requirements.572If you have no completed stored recording, [start a new session with relevant saved text history](https://developers.openai.com/api/docs/guides/live-conversations#seed-a-session-with-prior-conversation). See [GPT-Live data controls](https://developers.openai.com/api/docs/guides/data-residency#v1livesessions) for storage requirements.

567 573 

568For example, set this field in the source session’s WebSocket `session.start` configuration or WebRTC creation request:574For example, set this field in the source session’s WebSocket `session.start` configuration or WebRTC creation request:

569 575 


593 599 

594Set `OPENAI_API_KEY`. The examples use the stored source session ID saved by your application. They confirm startup and then close the fork. To continue the conversation, send and receive audio after `session.started` using the [WebSocket connection flow](https://developers.openai.com/api/docs/guides/voice-websockets?api=live). See the [fork WebSocket reference](https://developers.openai.com/api/reference/resources/live/fork-websocket) for the startup fields and events.600Set `OPENAI_API_KEY`. The examples use the stored source session ID saved by your application. They confirm startup and then close the fork. To continue the conversation, send and receive audio after `session.started` using the [WebSocket connection flow](https://developers.openai.com/api/docs/guides/voice-websockets?api=live). See the [fork WebSocket reference](https://developers.openai.com/api/reference/resources/live/fork-websocket) for the startup fields and events.

595 601 

596```javascript602```typescript

597import OpenAI from "openai";603import OpenAI from "openai";

598import { ForksWS } from "openai/resources/live/forks/ws";604import { ForksWS } from "openai/resources/live/forks/ws";

599 605 

600async function forkSession(sourceSessionId) {606async function forkSession(sourceSessionId: string) {

601 const ws = new ForksWS(new OpenAI(), { session_id: sourceSessionId });607 const ws = new ForksWS(new OpenAI(), { session_id: sourceSessionId });

602 let finalized = false;608 let finalized = false;

603 let closeRequested = false;609 let closeRequested = false;


779 785 

780Create a new SDP offer in your frontend and send it to your backend. The following backend examples use that offer and the stored source session ID from your application:786Create a new SDP offer in your frontend and send it to your backend. The following backend examples use that offer and the stored source session ID from your application:

781 787 

782```javascript788```typescript

783import OpenAI from "openai";789import OpenAI from "openai";

784 790 

785async function forkSession(sourceSessionId, offerSdp) {791async function forkSession(sourceSessionId: string, offerSdp: string) {

786 const client = new OpenAI();792 const client = new OpenAI();

787 const fork = await client.live.sessions.fork(sourceSessionId, {793 const fork = await client.live.sessions.fork(sourceSessionId, {

788 transport: { type: "webrtc", sdp: offerSdp },794 transport: { type: "webrtc", sdp: offerSdp },


864 870 

865After the stored recording is finalized, download its audio with `GET /v1/live/sessions/{session_id}/content`. The response is binary stereo WAV, with input audio in the left channel and output audio in the right channel. The examples use the stored session ID from your application and stream the response to `recording.wav`:871After the stored recording is finalized, download its audio with `GET /v1/live/sessions/{session_id}/content`. The response is binary stereo WAV, with input audio in the left channel and output audio in the right channel. The examples use the stored session ID from your application and stream the response to `recording.wav`:

866 872 

867```javascript873```typescript

868import OpenAI from "openai";874import OpenAI from "openai";

869import { createWriteStream } from "node:fs";875import { createWriteStream } from "node:fs";

870import { pipeline } from "node:stream/promises";876import { pipeline } from "node:stream/promises";

871 877 

872async function downloadRecording(sessionId) {878async function downloadRecording(sessionId: string) {

873 const client = new OpenAI();879 const client = new OpenAI();

874 const response = await client.live.sessions.downloadRecording(sessionId);880 const response = await client.live.sessions.downloadRecording(sessionId);

875 if (!response.body) throw new Error("Recording response has no body");881 if (!response.body) throw new Error("Recording response has no body");

Details

46 46 

47Add this delegation configuration when [creating your Live session](https://developers.openai.com/api/docs/guides/live). Choose the Responses model independently of the voice model:47Add this delegation configuration when [creating your Live session](https://developers.openai.com/api/docs/guides/live). Choose the Responses model independently of the voice model:

48 48 

49```javascript49```typescript

50export const session = {50export const session = {

51 model: "gpt-live-1",51 model: "gpt-live-1",

52 delegation: {52 delegation: {


212 212 

213After executing the authorized operation, append the result as a Responses item:213After executing the authorized operation, append the result as a Responses item:

214 214 

215```javascript215```typescript

216export function sendUpdate(connection) {216import type { ClientEvent } from "openai/resources/live/live";

217 

218export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

217 connection.send({219 connection.send({

218 type: "response.item.create",220 type: "response.item.create",

219 event_id: "tool_result_1",221 event_id: "tool_result_1",


297 299 

298Then explicitly continue the response:300Then explicitly continue the response:

299 301 

300```javascript302```typescript

301export function sendUpdate(connection) {303import type { ClientEvent } from "openai/resources/live/live";

304 

305export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

302 connection.send({306 connection.send({

303 type: "response.create",307 type: "response.create",

304 event_id: "continue_1",308 event_id: "continue_1",


364 368 

365Set `delegation` when [creating your Live session](https://developers.openai.com/api/docs/guides/live):369Set `delegation` when [creating your Live session](https://developers.openai.com/api/docs/guides/live):

366 370 

367```javascript371```typescript

368export const session = {372export const session = {

369 model: "gpt-live-1",373 model: "gpt-live-1",

370 delegation: {374 delegation: {


438 442 

439Return a result using that ID:443Return a result using that ID:

440 444 

441```javascript445```typescript

442export function sendUpdate(connection) {446import type { ClientEvent } from "openai/resources/live/live";

447 

448export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

443 connection.send({449 connection.send({

444 type: "session.commentary.append",450 type: "session.commentary.append",

445 event_id: "result_123",451 event_id: "result_123",


556 562 

557For quiet progress during a client-managed task:563For quiet progress during a client-managed task:

558 564 

559```javascript565```typescript

560export function sendUpdate(connection) {566import type { ClientEvent } from "openai/resources/live/live";

567 

568export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

561 connection.send({569 connection.send({

562 type: "session.thinking.append",570 type: "session.thinking.append",

563 event_id: "availability_progress",571 event_id: "availability_progress",


624 632 

625For a confirmed booking, send the result the user should hear:633For a confirmed booking, send the result the user should hear:

626 634 

627```javascript635```typescript

628export function sendUpdate(connection) {636import type { ClientEvent } from "openai/resources/live/live";

637 

638export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

629 connection.send({639 connection.send({

630 type: "session.commentary.append",640 type: "session.commentary.append",

631 event_id: "appointment_result",641 event_id: "appointment_result",


694 704 

695For example, after your application blocks a request under its guardrails, you can redirect the conversation:705For example, after your application blocks a request under its guardrails, you can redirect the conversation:

696 706 

697```javascript707```typescript

698export function sendUpdate(connection) {708import type { ClientEvent } from "openai/resources/live/live";

709 

710export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

699 connection.send({711 connection.send({

700 type: "session.instructions.append",712 type: "session.instructions.append",

701 event_id: "guardrail_block_17",713 event_id: "guardrail_block_17",


845 857 

846With Responses delegation, queue a user message for the backend:858With Responses delegation, queue a user message for the backend:

847 859 

848```javascript860```typescript

849export function sendUpdate(connection) {861import type { ClientEvent } from "openai/resources/live/live";

862 

863export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

850 connection.send({864 connection.send({

851 type: "response.item.create",865 type: "response.item.create",

852 event_id: "typed_order_number",866 event_id: "typed_order_number",

Details

253 253 

254**After: GPT-Live result**254**After: GPT-Live result**

255 255 

256```javascript256```typescript

257export function sendUpdate(connection) {257import type { ClientEvent } from "openai/resources/live/live";

258 

259export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

258 connection.send({260 connection.send({

259 type: "response.item.create",261 type: "response.item.create",

260 event_id: "availability_result_1",262 event_id: "availability_result_1",


339 341 

340After submitting every required function result, continue the backend:342After submitting every required function result, continue the backend:

341 343 

342```javascript344```typescript

343export function sendUpdate(connection) {345import type { ClientEvent } from "openai/resources/live/live";

346 

347export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

344 connection.send({348 connection.send({

345 type: "response.create",349 type: "response.create",

346 event_id: "continue_availability_1",350 event_id: "continue_availability_1",


476 480 

477Connect a client delegation to your agent481Connect a client delegation to your agent

478 482 

479```javascript483```typescript

480async function handleDelegation(event, app) {484import type {

485 ServerEvent,

486 CommentaryAppendEvent,

487 DelegationCreatedEvent,

488} from "openai/resources/live/live";

489 

490type AgentContext = {

491 revision: number;

492 recentConversation: string;

493 task: string;

494};

495type DelegationApp = {

496 readContext(): AgentContext | null;

497 runAgent(context: AgentContext): Promise<string>;

498 currentRevision(): number;

499 send(event: CommentaryAppendEvent): void;

500};

501 

502async function handleDelegation(event: ServerEvent, app: DelegationApp) {

481 if (503 if (

482 event.type !== "session.delegation.created" ||504 event.type !== "session.delegation.created" ||

483 event.delegation?.target !== "client"505 event.delegation?.target !== "client"

Details

218 218 

219Reuse text-only message input219Reuse text-only message input

220 220 

221```javascript221```typescript

222const context = [222const context: { role: "system" | "user"; content: string }[] = [

223 { role: "system", content: "You are a helpful assistant." },223 { role: "system", content: "You are a helpful assistant." },

224 { role: "user", content: "Hello!" },224 { role: "user", content: "Hello!" },

225];225];


425 from `completion.choices[0].message.content`.425 from `completion.choices[0].message.content`.

426 Generate text from a model426 Generate text from a model

427 427 

428```javascript428```typescript

429import OpenAI from "openai";429import OpenAI from "openai";

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

431 431 


562 and read generated text from `response.output_text`.562 and read generated text from `response.output_text`.

563 Generate text from a model563 Generate text from a model

564 564 

565```javascript565```typescript

566import OpenAI from "openai";566import OpenAI from "openai";

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

568 568 


709 `messages` array on each request.709 `messages` array on each request.

710 Multi-turn conversation710 Multi-turn conversation

711 711 

712```javascript712```typescript

713let messages = [713let messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [

714 { role: "system", content: "You are a helpful assistant." },714 { role: "system", content: "You are a helpful assistant." },

715 { role: "user", content: "What is the capital of France?" },715 { role: "user", content: "What is the capital of France?" },

716];716];


868 input of another.868 input of another.

869 Multi-turn conversation869 Multi-turn conversation

870 870 

871```javascript871```typescript

872import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";872import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

873 873 

874let context = [{ role: "user", content: "What is the capital of France?" }];874let context: OpenAI.Responses.ResponseInput = [

875 { role: "user", content: "What is the capital of France?" },

876];

875 877 

876const res1 = await client.responses.create({878const res1 = await client.responses.create({

877 model: "gpt-6-astra",879 model: "gpt-6-astra",


1054 and create response chains or forks.1056 and create response chains or forks.

1055 Multi-turn conversation1057 Multi-turn conversation

1056 1058 

1057```javascript1059```typescript

1058const res1 = await client.responses.create({1060const res1 = await client.responses.create({

1059 model: "gpt-6-astra",1061 model: "gpt-6-astra",

1060 input: "What is the capital of France?",1062 input: "What is the capital of France?",


1286 1288 

1287 Structured Outputs1289 Structured Outputs

1288 1290 

1289```javascript1291```typescript

1290const completion = await openai.chat.completions.create({1292const completion = await openai.chat.completions.create({

1291 model: "gpt-6-astra",1293 model: "gpt-6-astra",

1292 messages: [1294 messages: [


1577 1579 

1578 Structured Outputs1580 Structured Outputs

1579 1581 

1580```javascript1582```typescript

1581const response = await openai.responses.create({1583const response = await openai.responses.create({

1582 model: "gpt-6-astra",1584 model: "gpt-6-astra",

1583 input: "Jane, 54 years old",1585 input: "Jane, 54 years old",


1860 require the Responses API for tool calling.1862 require the Responses API for tool calling.

1861 Web search tool1863 Web search tool

1862 1864 

1863```javascript1865```typescript

1864async function web_search(query) {1866async function web_search(query: string) {

1865 const res = await fetch(`https://api.example.com/search?q=${query}`);1867 const res = await fetch(`https://api.example.com/search?q=${query}`);

1866 const data = await res.json();1868 const data = await res.json();

1867 return data.results;1869 return data.results;


2042 With Responses, you can specify the tools that you want the model to use.2044 With Responses, you can specify the tools that you want the model to use.

2043 Web search tool2045 Web search tool

2044 2046 

2045```javascript2047```typescript

2046const answer = await client.responses.create({2048const answer = await client.responses.create({

2047 model: "gpt-6-astra",2049 model: "gpt-6-astra",

2048 input: "Who is the current president of France?",2050 input: "Who is the current president of France?",

Details

37## Limitations37## Limitations

38 38 

39- GPT-6 Astra and GPT-6.1 Sol do not support the `none` reasoning effort; GPT-6.1 Terra, GPT-6 Sol, and GPT-6 Luna do.39- GPT-6 Astra and GPT-6.1 Sol do not support the `none` reasoning effort; GPT-6.1 Terra, GPT-6 Sol, and GPT-6 Luna do.

40- Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna, but not GPT-6 Astra or GPT-6 Sol. [Ultrafast mode](https://developers.openai.com/api/docs/guides/ultrafast-mode) for GPT-6.1 Sol supports US and EU data residency and global processing. GPT-6 Astra Ultrafast supports US data residency and global processing only. See [data residency eligibility](https://developers.openai.com/api/docs/guides/your-data#which-models-and-features-are-eligible-for-data-residency).40- Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna, but not GPT-6 Astra or GPT-6 Sol. [Ultrafast mode](https://developers.openai.com/api/docs/guides/ultrafast-mode) for GPT-6.1 Sol supports US and EU data residency and global processing. GPT-6 Astra Ultrafast supports US data residency and global processing only. See [data residency eligibility](https://developers.openai.com/api/docs/guides/data-residency#which-models-and-features-are-eligible-for-data-residency).

41 41 

42<a id="prompting-best-practices" className="scroll-mt-[110px]"></a>42<a id="prompting-best-practices" className="scroll-mt-[110px]"></a>

43 43 

Details

29 29 

30Generate a response with moderation scores30Generate a response with moderation scores

31 31 

32```javascript32```typescript

33import OpenAI from "openai";33import OpenAI from "openai";

34 34 

35const client = new OpenAI();35const client = new OpenAI();


46 moderation: { model: "omni-moderation-latest" },46 moderation: { model: "omni-moderation-latest" },

47});47});

48 48 

49if (!response.moderation) {

50 throw new Error("The API did not return the requested moderation results.");

51}

52 

49const inputModeration = response.moderation.input;53const inputModeration = response.moderation.input;

50const outputModeration = response.moderation.output;54const outputModeration = response.moderation.output;

51if (inputModeration.type === "error") {55if (inputModeration.type === "error") {


224 228 

225Get classification information for a text input229Get classification information for a text input

226 230 

227```javascript231```typescript

228import OpenAI from "openai";232import OpenAI from "openai";

229const openai = new OpenAI();233const openai = new OpenAI();

230 234 


346 350 

347Get classification information for image and text input351Get classification information for image and text input

348 352 

349```javascript353```typescript

350import OpenAI from "openai";354import OpenAI from "openai";

351const openai = new OpenAI();355const openai = new OpenAI();

352 356 

Details

10 10 

11Predicted Outputs are particularly useful for regenerating text documents and code files with small modifications. Let's say you want the [GPT-4o model](https://developers.openai.com/api/docs/models#gpt-4o) to refactor a piece of JavaScript code, and convert the `username` property of the `User` class to be `email` instead:11Predicted Outputs are particularly useful for regenerating text documents and code files with small modifications. Let's say you want the [GPT-4o model](https://developers.openai.com/api/docs/models#gpt-4o) to refactor a piece of JavaScript code, and convert the `username` property of the `User` class to be `email` instead:

12 12 

13```javascript13```typescript

14class User {14class User {

15 firstName = "";15 firstName = "";

16 lastName = "";16 lastName = "";


27 27 

28Refactor a JavaScript class with a Predicted Output28Refactor a JavaScript class with a Predicted Output

29 29 

30```javascript30```typescript

31import OpenAI from "openai";31import OpenAI from "openai";

32 32 

33const code = `33const code = `


317 317 

318Predicted Outputs with streaming318Predicted Outputs with streaming

319 319 

320```javascript320```typescript

321import OpenAI from "openai";321import OpenAI from "openai";

322 322 

323const code = `323const code = `


573 573 

574When providing prediction text, your prediction can appear anywhere within the generated response, and still provide latency reduction for the response. Let's say your predicted text is the simple [Hono](https://hono.dev/) server shown below:574When providing prediction text, your prediction can appear anywhere within the generated response, and still provide latency reduction for the response. Let's say your predicted text is the simple [Hono](https://hono.dev/) server shown below:

575 575 

576```javascript576```typescript

577import { serve } from "@hono/node-server";577import { serve } from "@hono/node-server";

578import { serveStatic } from "@hono/node-server/serve-static";578import { serveStatic } from "@hono/node-server/serve-static";

579import { Hono } from "hono";579import { Hono } from "hono";


613 613 

614The response to the prompt might look something like this:614The response to the prompt might look something like this:

615 615 

616```javascript616```typescript

617import { serve } from "@hono/node-server";617import { serve } from "@hono/node-server";

618import { serveStatic } from "@hono/node-server/serve-static";618import { serveStatic } from "@hono/node-server/serve-static";

619import { Hono } from "hono";619import { Hono } from "hono";

Details

905 {" - ZDR eligibility, endpoint-specific retention, and exceptions."}905 {" - ZDR eligibility, endpoint-specific retention, and exceptions."}

906 </li>906 </li>

907 <li>907 <li>

908 [{"Data residency"}](https://developers.openai.com/api/docs/guides/your-data#data-residency-controls)908 [{"Data residency"}](https://developers.openai.com/api/docs/guides/data-residency)

909 {" - Supported regions and processing boundaries."}909 {" - Supported regions and processing boundaries."}

910 </li>910 </li>

911</ul>911</ul>

Details

263 263 

264Cached states live on individual machines, where traffic above 15 requests per minute can lead to overflow routing. A request can reuse a cached prefix only if it reaches a machine holding a matching entry that has not expired. Routing requests to the right machine is therefore important for cache reuse.264Cached states live on individual machines, where traffic above 15 requests per minute can lead to overflow routing. A request can reuse a cached prefix only if it reaches a machine holding a matching entry that has not expired. Routing requests to the right machine is therefore important for cache reuse.

265 265 

266Caches are not shared across organizations and cannot be reused across [regional processing boundaries](https://developers.openai.com/api/docs/guides/your-data#data-residency-controls).266Caches are not shared across organizations and cannot be reused across [regional processing boundaries](https://developers.openai.com/api/docs/guides/data-residency).

267 267 

268OpenAI handles routing automatically. Within an organization and processing region, routing for a given model depends on:268OpenAI handles routing automatically. Within an organization and processing region, routing for a given model depends on:

269 269 


649 649 

650Calculate input cost with one cache-write rate650Calculate input cost with one cache-write rate

651 651 

652```javascript652```typescript

653function calculateInputCost(653function calculateInputCost(

654 usage,654 usage: {

655 inputPricePerMillion,655 input_tokens: number;

656 input_tokens_details: { cached_tokens: number; cache_write_tokens: number };

657 },

658 inputPricePerMillion: number,

656 cacheInputMultiplier = 0.1,659 cacheInputMultiplier = 0.1,

657 cacheWriteMultiplier = 1.25660 cacheWriteMultiplier = 1.25

658) {661) {


1116 1119 

1117The prompt cache stores key-value (KV) tensors rather than the original prompt text. These tensors may be stored as encrypted application state in GPU-local storage, with a maximum retention period of 24 hours. See [Cache lifetime](#cache-lifetime) for model-specific cache lifetimes and refresh behavior.1120The prompt cache stores key-value (KV) tensors rather than the original prompt text. These tensors may be stored as encrypted application state in GPU-local storage, with a maximum retention period of 24 hours. See [Cache lifetime](#cache-lifetime) for model-specific cache lifetimes and refresh behavior.

1118 1121 

1119Caches are not shared across organizations and cannot be reused across [regional processing boundaries](https://developers.openai.com/api/docs/guides/your-data#data-residency-controls). For details about data handling and ZDR eligibility across API features, see [Your data](https://developers.openai.com/api/docs/guides/your-data).1122Caches are not shared across organizations and cannot be reused across [regional processing boundaries](https://developers.openai.com/api/docs/guides/data-residency). For details about data handling and ZDR eligibility across API features, see [Your data](https://developers.openai.com/api/docs/guides/your-data).

Details

6 6 

7 7 

8 8 

9Here's a simple example using the [Responses API](https://developers.openai.com/api/reference/resources/responses).9Here's an example using the [Responses API](https://developers.openai.com/api/reference/resources/responses).

10 10 

11Generate text from a simple prompt11Generate text from a simple prompt

12 12 

13```javascript13```typescript

14import OpenAI from "openai";14import OpenAI from "openai";

15const client = new OpenAI();15const client = new OpenAI();

16 16 


131```131```

132 132 

133 133 

134An array of content generated by the model is in the `output` property of the response. In this simple example, we have just one output which looks like this:134An array of content generated by the model is in the `output` property of the response. In this example, we have just one output which looks like this:

135 135 

136```json136```json

137[137[


194 194 

195Generate text with instructions195Generate text with instructions

196 196 

197```javascript197```typescript

198import OpenAI from "openai";198import OpenAI from "openai";

199const client = new OpenAI();199const client = new OpenAI();

200 200 


337 337 

338Generate text with messages using different roles338Generate text with messages using different roles

339 339 

340```javascript340```typescript

341import OpenAI from "openai";341import OpenAI from "openai";

342const client = new OpenAI();342const client = new OpenAI();

343 343 


535The [OpenAI model spec](https://model-spec.openai.com/2025-02-12.html#chain_of_command) describes how our models give different levels of priority to messages with different roles.535The [OpenAI model spec](https://model-spec.openai.com/2025-02-12.html#chain_of_command) describes how our models give different levels of priority to messages with different roles.

536 536 

537| `developer` | `user` | `assistant` |537| `developer` | `user` | `assistant` |

538| ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |538| ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |

539| `developer` messages are instructions provided by the application developer, prioritized ahead of `user` messages. | `user` messages are instructions provided by an end user, prioritized behind `developer` messages. | Messages generated by the model have the `assistant` role. |539| `developer` messages are instructions provided by the developer, prioritized ahead of `user` messages. | `user` messages are instructions provided by an end user, prioritized behind `developer` messages. | Messages generated by the model have the `assistant` role. |

540 540 

541A multi-turn conversation may consist of several messages of these types, along with other content types provided by both you and the model. Learn more about [managing conversation state here](https://developers.openai.com/api/docs/guides/conversation-state).541A multi-turn conversation may consist of several messages of these types, along with other content types provided by both you and the model. Learn more about [managing conversation state here](https://developers.openai.com/api/docs/guides/conversation-state).

542 542 


622 622 

623 Send a prompt to generate code through the API623 Send a prompt to generate code through the API

624 624 

625```javascript625```typescript

626import fs from "fs/promises";626import fs from "fs/promises";

627import OpenAI from "openai";627import OpenAI from "openai";

628const client = new OpenAI();628const client = new OpenAI();


811 811 

812## Include relevant context information812## Include relevant context information

813 813 

814It is often useful to include additional context information the model can use to generate a response within the prompt you give the model. There are a few common reasons why you might do this:814It is often useful to include additional context information the model can use to generate a response within the prompt you give the model. Common reasons include:

815 815 

816- To give the model access to proprietary data, or any other data outside the data set the model was trained on.816- To give the model access to proprietary data, or any other data outside the data set the model was trained on.

817- To constrain the model's response to a specific set of resources that you have determined will be most beneficial.817- To constrain the model's response to a specific set of resources that you have determined will be most beneficial.


924 924 

925 925 

926 926 

927For agentic and long-running rollouts with `gpt-6-astra`, focus your prompts on three core practices: plan tasks thoroughly to ensure complete resolution, provide clear preambles for major tool usage decisions, and use a TODO tool to track workflow and progress in an organized manner.927For agentic and long-running tasks with `gpt-6-astra`, ask the model to plan the work from start to finish, explain major tool calls before making them, and track progress with a task list tool.

928 928 

929**Planning and persistence**929**Planning and persistence**

930Instruct the model to resolve the full query before yielding control, decomposing it into sub-tasks and reflecting after each tool call to confirm completeness.930Instruct the model to resolve the full query before yielding control, decomposing it into sub-tasks and reflecting after each tool call to confirm completeness.


956```956```

957 957 

958 958 

959**Progress tracking with rubrics and TODOs**959**Progress tracking with rubrics and task lists**

960 960 

961Use a TODO list tool or rubric to enforce structured planning and avoid missed steps.961Use a task list tool or rubric to enforce structured planning and avoid missed steps.

962 962 

963For detailed guidance and prompt samples specific to building agents, see the [latest model prompting best practices](https://developers.openai.com/api/docs/guides/latest-model).963For detailed guidance and prompt samples specific to building agents, see the [latest model prompting best practices](https://developers.openai.com/api/docs/guides/latest-model).

964 964 


968 968 

969## Prompting reasoning models969## Prompting reasoning models

970 970 

971There are some differences to consider when prompting a [reasoning model](https://developers.openai.com/api/docs/guides/reasoning) versus prompting a GPT model. Generally speaking, reasoning models will provide better results on tasks with only high-level guidance. This differs from GPT models, which benefit from very precise instructions.971Consider the differences when prompting a [reasoning model](https://developers.openai.com/api/docs/guides/reasoning) versus prompting a GPT model. Generally speaking, reasoning models will provide better results on tasks with only high-level guidance. This differs from GPT models, which benefit from precise instructions.

972 972 

973You could think about the difference between reasoning and GPT models like this.973You could think about the difference between reasoning and GPT models like this.

974 974 

Details

27 27 

28 Text meta-prompt28 Text meta-prompt

29 29 

30```javascript30```typescript

31import OpenAI from "openai";31import OpenAI from "openai";

32 32 

33const client = new OpenAI();33const client = new OpenAI();


76 76 

77[optional: edge cases, details, and an area to call or repeat out specific important considerations]`;77[optional: edge cases, details, and an area to call or repeat out specific important considerations]`;

78 78 

79async function generatePrompt(taskOrPrompt) {79async function generatePrompt(taskOrPrompt: string) {

80 const completion = await client.chat.completions.create({80 const completion = await client.chat.completions.create({

81 model: "gpt-6-astra",81 model: "gpt-6-astra",

82 messages: [82 messages: [


442 442 

443 Audio meta-prompt443 Audio meta-prompt

444 444 

445```javascript445```typescript

446import OpenAI from "openai";446import OpenAI from "openai";

447 447 

448const client = new OpenAI();448const client = new OpenAI();


482 482 

483[optional: edge cases, details, and an area to call or repeat out specific important considerations]`;483[optional: edge cases, details, and an area to call or repeat out specific important considerations]`;

484 484 

485async function generatePrompt(taskOrPrompt) {485async function generatePrompt(taskOrPrompt: string) {

486 const completion = await client.chat.completions.create({486 const completion = await client.chat.completions.create({

487 model: "gpt-6-astra",487 model: "gpt-6-astra",

488 messages: [488 messages: [


807 807 

808 Text meta-prompt for edits808 Text meta-prompt for edits

809 809 

810```javascript810```typescript

811import OpenAI from "openai";811import OpenAI from "openai";

812 812 

813const client = new OpenAI();813const client = new OpenAI();


875[optional: edge cases, details, and an area to call or repeat out specific important considerations]875[optional: edge cases, details, and an area to call or repeat out specific important considerations]

876[NOTE: you must start with a <reasoning> section. the immediate next token you produce should be <reasoning>]`;876[NOTE: you must start with a <reasoning> section. the immediate next token you produce should be <reasoning>]`;

877 877 

878async function generatePrompt(taskOrPrompt) {878async function generatePrompt(taskOrPrompt: string) {

879 const completion = await client.chat.completions.create({879 const completion = await client.chat.completions.create({

880 model: "gpt-6-astra",880 model: "gpt-6-astra",

881 messages: [881 messages: [


1336 1336 

1337 Audio meta-prompt for edits1337 Audio meta-prompt for edits

1338 1338 

1339```javascript1339```typescript

1340import OpenAI from "openai";1340import OpenAI from "openai";

1341 1341 

1342const client = new OpenAI();1342const client = new OpenAI();


1395[optional: edge cases, details, and an area to call or repeat out specific important considerations]1395[optional: edge cases, details, and an area to call or repeat out specific important considerations]

1396[NOTE: you must start with a <reasoning> section. the immediate next token you produce should be <reasoning>]`;1396[NOTE: you must start with a <reasoning> section. the immediate next token you produce should be <reasoning>]`;

1397 1397 

1398async function generatePrompt(taskOrPrompt) {1398async function generatePrompt(taskOrPrompt: string) {

1399 const completion = await client.chat.completions.create({1399 const completion = await client.chat.completions.create({

1400 model: "gpt-6-astra",1400 model: "gpt-6-astra",

1401 messages: [1401 messages: [


1864 1864 

1865 Structured output meta-schema1865 Structured output meta-schema

1866 1866 

1867```javascript1867```typescript

1868import OpenAI from "openai";1868import OpenAI from "openai";

1869 1869 

1870const client = new OpenAI();1870const client = new OpenAI();


2092 "additionalProperties": false2092 "additionalProperties": false

2093}`;2093}`;

2094 2094 

2095async function generateSchema(description) {2095async function generateSchema(description: string) {

2096 const completion = await client.chat.completions.create({2096 const completion = await client.chat.completions.create({

2097 model: "gpt-5.6-terra",2097 model: "gpt-5.6-terra",

2098 response_format: { type: "json_schema", json_schema: metaSchema },2098 response_format: { type: "json_schema", json_schema: metaSchema },


3693 3693 

3694 Structured output meta-schema3694 Structured output meta-schema

3695 3695 

3696```javascript3696```typescript

3697import OpenAI from "openai";3697import OpenAI from "openai";

3698 3698 

3699const client = new OpenAI();3699const client = new OpenAI();


3905 }3905 }

3906}`;3906}`;

3907 3907 

3908async function generateFunctionSchema(description) {3908async function generateFunctionSchema(description: string) {

3909 const completion = await client.chat.completions.create({3909 const completion = await client.chat.completions.create({

3910 model: "gpt-5.6-terra",3910 model: "gpt-5.6-terra",

3911 response_format: { type: "json_schema", json_schema: metaSchema },3911 response_format: { type: "json_schema", json_schema: metaSchema },

Details

37## Limitations37## Limitations

38 38 

39- GPT-6 Astra and GPT-6.1 Sol do not support the `none` reasoning effort; GPT-6.1 Terra, GPT-6 Sol, and GPT-6 Luna do.39- GPT-6 Astra and GPT-6.1 Sol do not support the `none` reasoning effort; GPT-6.1 Terra, GPT-6 Sol, and GPT-6 Luna do.

40- Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna, but not GPT-6 Astra or GPT-6 Sol. [Ultrafast mode](https://developers.openai.com/api/docs/guides/ultrafast-mode) for GPT-6.1 Sol supports US and EU data residency and global processing. GPT-6 Astra Ultrafast supports US data residency and global processing only. See [data residency eligibility](https://developers.openai.com/api/docs/guides/your-data#which-models-and-features-are-eligible-for-data-residency).40- Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna, but not GPT-6 Astra or GPT-6 Sol. [Ultrafast mode](https://developers.openai.com/api/docs/guides/ultrafast-mode) for GPT-6.1 Sol supports US and EU data residency and global processing. GPT-6 Astra Ultrafast supports US data residency and global processing only. See [data residency eligibility](https://developers.openai.com/api/docs/guides/data-residency#which-models-and-features-are-eligible-for-data-residency).

41 41 

42<a id="prompting-best-practices" className="scroll-mt-[110px]"></a>42<a id="prompting-best-practices" className="scroll-mt-[110px]"></a>

43 43 

Details

14 14 

15Use a prompt object15Use a prompt object

16 16 

17```javascript17```typescript

18import OpenAI from "openai";18import OpenAI from "openai";

19 19 

20const client = new OpenAI();20const client = new OpenAI();


152 152 

153Inline the prompt in code153Inline the prompt in code

154 154 

155```javascript155```typescript

156import OpenAI from "openai";156import OpenAI from "openai";

157 157 

158const client = new OpenAI();158const client = new OpenAI();


345 345 

346Build prompts with a helper function346Build prompts with a helper function

347 347 

348```javascript348```typescript

349import OpenAI from "openai";349import OpenAI from "openai";

350 350 

351const client = new OpenAI();351const client = new OpenAI();

352 352 

353function buildSupportPrompt({ customerName, issue }) {353function buildSupportPrompt({

354 customerName,

355 issue,

356}: {

357 customerName: string;

358 issue: string;

359}): OpenAI.Responses.ResponseInput {

354 return [360 return [

355 {361 {

356 role: "system",362 role: "system",

Details

19 19 

20Start a realtime voice session20Start a realtime voice session

21 21 

22```javascript22```typescript

23import { RealtimeAgent, RealtimeSession } from "@openai/agents/realtime";23import { RealtimeAgent, RealtimeSession } from "@openai/agents/realtime";

24 24 

25const ephemeralKey = process.env.OPENAI_REALTIME_EPHEMERAL_KEY;25const ephemeralKey = process.env.OPENAI_REALTIME_EPHEMERAL_KEY;

Details

38 38 

39Update the system instructions used by the model in this session39Update the system instructions used by the model in this session

40 40 

41```javascript41```typescript

42const event = {42const event = {

43 type: "session.update",43 type: "session.update",

44 session: {44 session: {


274 274 

275Create a conversation item with user input275Create a conversation item with user input

276 276 

277```javascript277```typescript

278const event = {278const event = {

279 type: "conversation.item.create",279 type: "conversation.item.create",

280 item: {280 item: {


382 382 

383Generate a text-only response383Generate a text-only response

384 384 

385```javascript385```typescript

386const event = {386const event = {

387 type: "response.create",387 type: "response.create",

388 response: {388 response: {


467 467 

468Listen for response.done to see the final results468Listen for response.done to see the final results

469 469 

470```javascript470```typescript

471function handleEvent(message) {471function handleEvent(message: import("ws").RawData | MessageEvent<string>) {

472 const data = "data" in message ? message.data : message.toString();472 const data = "data" in message ? message.data : message.toString();

473 const serverEvent = JSON.parse(data);473 const serverEvent = JSON.parse(data);

474 if (serverEvent.type === "response.done") {474 if (serverEvent.type === "response.done") {


649 649 

650The example code from the [WebRTC connection guide](https://developers.openai.com/api/docs/guides/voice-webrtc?api=realtime) shows a basic example of configuring both local and remote audio using browser APIs:650The example code from the [WebRTC connection guide](https://developers.openai.com/api/docs/guides/voice-webrtc?api=realtime) shows a basic example of configuring both local and remote audio using browser APIs:

651 651 

652```javascript652```typescript

653// Create a peer connection653// Create a peer connection

654const pc = new RTCPeerConnection();654const pc = new RTCPeerConnection();

655 655 


807 807 

808Append audio input bytes to the conversation808Append audio input bytes to the conversation

809 809 

810```javascript810```typescript

811import fs from "fs";811import fs from "fs";

812import decodeAudio from "audio-decode";812import decodeAudio from "audio-decode";

813 813 

814// Converts Float32Array of audio data to PCM16 ArrayBuffer814// Converts Float32Array of audio data to PCM16 ArrayBuffer

815function floatTo16BitPCM(float32Array) {815function floatTo16BitPCM(float32Array: Float32Array) {

816 const buffer = new ArrayBuffer(float32Array.length * 2);816 const buffer = new ArrayBuffer(float32Array.length * 2);

817 const view = new DataView(buffer);817 const view = new DataView(buffer);

818 let offset = 0;818 let offset = 0;


828}828}

829 829 

830// Converts a Float32Array to base64-encoded PCM16 data830// Converts a Float32Array to base64-encoded PCM16 data

831function base64EncodeAudio(float32Array) {831function base64EncodeAudio(float32Array: Float32Array<ArrayBufferLike>) {

832 const arrayBuffer = floatTo16BitPCM(float32Array);832 const arrayBuffer = floatTo16BitPCM(float32Array);

833 let binary = "";833 let binary = "";

834 let bytes = new Uint8Array(arrayBuffer);834 let bytes = new Uint8Array(arrayBuffer);


992 992 

993Create full audio input conversation items993Create full audio input conversation items

994 994 

995```javascript995```typescript

996const fullAudio = "<a base64-encoded string of audio bytes>";996const fullAudio = "<a base64-encoded string of audio bytes>";

997 997 

998const event = {998const event = {


1140 1140 

1141Listen for response.output_audio.delta events1141Listen for response.output_audio.delta events

1142 1142 

1143```javascript1143```typescript

1144function handleEvent(message) {1144function handleEvent(message: { toString: () => string }) {

1145 const serverEvent = JSON.parse(message.toString());1145 const serverEvent = JSON.parse(message.toString());

1146 if (serverEvent.type === "response.output_audio.delta") {1146 if (serverEvent.type === "response.output_audio.delta") {

1147 const audio = Buffer.from(serverEvent.delta, "base64");1147 const audio = Buffer.from(serverEvent.delta, "base64");


1236 1236 

1237Add an image to the conversation1237Add an image to the conversation

1238 1238 

1239```javascript1239```typescript

1240const base64Image = "<a base64-encoded string of image bytes>";1240const base64Image = "<a base64-encoded string of image bytes>";

1241 1241 

1242const event = {1242const event = {


1346 1346 

1347Create an out-of-band model response1347Create an out-of-band model response

1348 1348 

1349```javascript1349```typescript

1350const prompt = `1350const prompt = `

1351Analyze the conversation so far. If it is related to support, output1351Analyze the conversation so far. If it is related to support, output

1352"support". If it is related to sales, output "sales".1352"support". If it is related to sales, output "sales".


1484 1484 

1485Create an out-of-band model response1485Create an out-of-band model response

1486 1486 

1487```javascript1487```typescript

1488function handleEvent(message) {1488function handleEvent(message: import("ws").RawData | MessageEvent<string>) {

1489 const data = "data" in message ? message.data : message.toString();1489 const data = "data" in message ? message.data : message.toString();

1490 const serverEvent = JSON.parse(data);1490 const serverEvent = JSON.parse(data);

1491 if (1491 if (


1630 1630 

1631Listen for out-of-band model response with custom context1631Listen for out-of-band model response with custom context

1632 1632 

1633```javascript1633```typescript

1634const existingItemId = "item_pizza";1634const existingItemId = "item_pizza";

1635ws.send(1635ws.send(

1636 JSON.stringify({1636 JSON.stringify({


1771 1771 

1772Insert no-context model responses into the default conversation1772Insert no-context model responses into the default conversation

1773 1773 

1774```javascript1774```typescript

1775const prompt = `1775const prompt = `

1776Say exactly the following:1776Say exactly the following:

1777I'm a little teapot, short and stout!1777I'm a little teapot, short and stout!


2052 2052 

2053Unlike HTTP requests and responses, where a response is implicitly tied to a request from the client, we need to use an `event_id` property on client events to know when one of them has triggered an error condition on the server. This technique is shown in the code below, where the client attempts to emit an unsupported event type.2053Unlike HTTP requests and responses, where a response is implicitly tied to a request from the client, we need to use an `event_id` property on client events to know when one of them has triggered an error condition on the server. This technique is shown in the code below, where the client attempts to emit an unsupported event type.

2054 2054 

2055```javascript2055```typescript

2056const event = {2056const event = {

2057 event_id: "my_awesome_event",2057 event_id: "my_awesome_event",

2058 type: "scooby.dooby.doo",2058 type: "scooby.dooby.doo",

Details

25 25 

26Configure a function tool with session.update26Configure a function tool with session.update

27 27 

28```javascript28```typescript

29const event = {29const event = {

30 type: "session.update",30 type: "session.update",

31 session: {31 session: {


214 214 

215Send function call output215Send function call output

216 216 

217```javascript217```typescript

218const event = {218const event = {

219 type: "conversation.item.create",219 type: "conversation.item.create",

220 item: {220 item: {


394 394 

395Configure an MCP tool with session.update395Configure an MCP tool with session.update

396 396 

397```javascript397```typescript

398const event = {398const event = {

399 type: "session.update",399 type: "session.update",

400 session: {400 session: {


556 556 

557Configure a Google Calendar connector557Configure a Google Calendar connector

558 558 

559```javascript559```typescript

560const event = {560const event = {

561 type: "session.update",561 type: "session.update",

562 session: {562 session: {


743 743 

744Listen for MCP events during a Realtime session744Listen for MCP events during a Realtime session

745 745 

746```javascript746```typescript

747function parseRealtimeEvent(rawMessage) {747import type WebSocket from "ws";

748import type {

749 ConversationItem,

750 RealtimeServerEvent,

751} from "openai/resources/realtime/realtime";

752 

753function parseRealtimeEvent(

754 rawMessage: string | WebSocket.RawData | MessageEvent<string>

755): RealtimeServerEvent {

748 if (typeof rawMessage === "string") {756 if (typeof rawMessage === "string") {

749 return JSON.parse(rawMessage);757 return JSON.parse(rawMessage);

750 }758 }

751 759 

752 if (typeof rawMessage?.data === "string") {760 if ("data" in rawMessage && typeof rawMessage.data === "string") {

753 return JSON.parse(rawMessage.data);761 return JSON.parse(rawMessage.data);

754 }762 }

755 763 

756 return JSON.parse(rawMessage.toString());764 return JSON.parse(rawMessage.toString());

757}765}

758 766 

759function getOutputText(item) {767function getOutputText(item: ConversationItem) {

760 if (item.type !== "message") return "";768 if (item.type !== "message") return "";

761 769 

762 return (item.content ?? [])770 return (item.content ?? [])


1009 1017 

1010Approve an MCP request1018Approve an MCP request

1011 1019 

1012```javascript1020```typescript

1013function approveMcpRequest(approvalRequestId) {1021function approveMcpRequest(approvalRequestId: string) {

1014 const event = {1022 const event = {

1015 type: "conversation.item.create",1023 type: "conversation.item.create",

1016 item: {1024 item: {


1139 1147 

1140Add MCP tools on one response1148Add MCP tools on one response

1141 1149 

1142```javascript1150```typescript

1143const event = {1151const event = {

1144 type: "response.create",1152 type: "response.create",

1145 response: {1153 response: {


1369 1377 

1370Reuse a previously defined connector1378Reuse a previously defined connector

1371 1379 

1372```javascript1380```typescript

1373const event = {1381const event = {

1374 type: "response.create",1382 type: "response.create",

1375 response: {1383 response: {

Details

40 40 

41Send audio chunks with `input_audio_buffer.append`:41Send audio chunks with `input_audio_buffer.append`:

42 42 

43```javascript43```typescript

44ws.send(44ws.send(

45 JSON.stringify({45 JSON.stringify({

46 type: "input_audio_buffer.append",46 type: "input_audio_buffer.append",


52 52 

53Send `input_audio_buffer.commit` at the end of each audio turn to receive the final transcript:53Send `input_audio_buffer.commit` at the end of each audio turn to receive the final transcript:

54 54 

55```javascript55```typescript

56ws.send(56ws.send(

57 JSON.stringify({57 JSON.stringify({

58 type: "input_audio_buffer.commit",58 type: "input_audio_buffer.commit",


67 67 

68Listen for incremental transcript deltas and completion events:68Listen for incremental transcript deltas and completion events:

69 69 

70```javascript70```typescript

71ws.on("message", (data) => {71ws.on("message", (data) => {

72 const event = JSON.parse(data);72 const event = JSON.parse(data);

73 73 

Details

32 32 

33Create a translation client secret33Create a translation client secret

34 34 

35```javascript35```typescript

36app.post("/session", async (req, res) => {36app.post("/session", async (req, res) => {

37 const language = req.body.targetLanguage ?? "es";37 const language = req.body.targetLanguage ?? "es";

38 38 


65 65 

66Connect a browser translation call66Connect a browser translation call

67 67 

68```javascript68```typescript

69const { value: clientSecret } = await fetch("/session", {69const { value: clientSecret } = await fetch("/session", {

70 method: "POST",70 method: "POST",

71 headers: { "Content-Type": "application/json" },71 headers: { "Content-Type": "application/json" },


129 129 

130Connect to a translation session130Connect to a translation session

131 131 

132```javascript132```typescript

133import WebSocket from "ws";133import WebSocket from "ws";

134 134 

135const ws = new WebSocket(135const ws = new WebSocket(


244 244 

245Configure the target language245Configure the target language

246 246 

247```javascript247```typescript

248ws.on("open", () => {248ws.on("open", () => {

249 ws.send(249 ws.send(

250 JSON.stringify({250 JSON.stringify({


325 325 

326Append source audio326Append source audio

327 327 

328```javascript328```typescript

329ws.send(329ws.send(

330 JSON.stringify({330 JSON.stringify({

331 type: "session.input_audio_buffer.append",331 type: "session.input_audio_buffer.append",


388 388 

389Listen for translated audio and transcripts389Listen for translated audio and transcripts

390 390 

391```javascript391```typescript

392ws.on("message", (data) => {392ws.on("message", (data) => {

393 const event = JSON.parse(data.toString());393 const event = JSON.parse(data.toString());

394 394 


497 497 

498Close a translation session498Close a translation session

499 499 

500```javascript500```typescript

501let translationSessionClosing = false;501let translationSessionClosing = false;

502let gotTranslationClosed = false;502let gotTranslationClosed = false;

503let drainDeadline;503let drainDeadline: ReturnType<typeof setTimeout> | undefined;

504 504 

505ws.on("close", () => {505ws.on("close", () => {

506 clearTimeout(drainDeadline);506 clearTimeout(drainDeadline);

Details

147 147 

148This application server supports standard WebRTC and WARP. The comment marked `WARP only` identifies the `dcid` forwarding needed for WARP:148This application server supports standard WebRTC and WARP. The comment marked `WARP only` identifies the `dcid` forwarding needed for WARP:

149 149 

150```javascript150```typescript

151import express from "express";151import express from "express";

152 152 

153const app = express();153const app = express();


256 256 

257After enabling the optimizations available in your browser, set `useWarp` to `true`. Choose any available data-channel ID and pass the same ID to the server. Comments marked `WARP only` identify the configuration and signaling that aren't needed for standard WebRTC:257After enabling the optimizations available in your browser, set `useWarp` to `true`. Choose any available data-channel ID and pass the same ID to the server. Comments marked `WARP only` identify the configuration and signaling that aren't needed for standard WebRTC:

258 258 

259```javascript259```typescript

260// WARP only: set to true after enabling the supported WARP optimizations.260// WARP only: set to true after enabling the supported WARP optimizations.

261const useWarp = false;261const useWarp = false;

262 262 

Details

17 17 

18Using a reasoning model in the Responses API18Using a reasoning model in the Responses API

19 19 

20```javascript20```typescript

21import OpenAI from "openai";21import OpenAI from "openai";

22 22 

23const openai = new OpenAI();23const openai = new OpenAI();


289 289 

290Handling incomplete responses290Handling incomplete responses

291 291 

292```javascript292```typescript

293import OpenAI from "openai";293import OpenAI from "openai";

294 294 

295const openai = new OpenAI();295const openai = new OpenAI();


313 313 

314if (314if (

315 response.status === "incomplete" &&315 response.status === "incomplete" &&

316 response.incomplete_details.reason === "max_output_tokens"316 response.incomplete_details?.reason === "max_output_tokens"

317) {317) {

318 console.log("Ran out of tokens");318 console.log("Ran out of tokens");

319 if (response.output_text?.length > 0) {319 if (response.output_text?.length > 0) {


532 532 

533Preserve reasoning with a previous response533Preserve reasoning with a previous response

534 534 

535```javascript535```typescript

536import OpenAI from "openai";536import OpenAI from "openai";

537 537 

538const client = new OpenAI();538const client = new OpenAI();


711 711 

712Preserve reasoning without storing responses712Preserve reasoning without storing responses

713 713 

714```javascript714```typescript

715import OpenAI from "openai";715import OpenAI from "openai";

716import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";716import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

717 717 

718const client = new OpenAI();718const client = new OpenAI();

719 719 

720const history = [720const history: OpenAI.Responses.ResponseInput = [

721 {721 {

722 role: "user",722 role: "user",

723 content: "Inspect this repository and identify the likely bug.",723 content: "Inspect this repository and identify the likely bug.",


970 970 

971Increase reasoning effort for a follow-up971Increase reasoning effort for a follow-up

972 972 

973```javascript973```typescript

974import OpenAI from "openai";974import OpenAI from "openai";

975 975 

976const client = new OpenAI();976const client = new OpenAI();


1180 1180 

1181Include a reasoning summary with the API response1181Include a reasoning summary with the API response

1182 1182 

1183```javascript1183```typescript

1184import OpenAI from "openai";1184import OpenAI from "openai";

1185const openai = new OpenAI();1185const openai = new OpenAI();

1186 1186 


1373 1373 

1374Round-trip assistant phase values1374Round-trip assistant phase values

1375 1375 

1376```javascript1376```typescript

1377import OpenAI from "openai";1377import OpenAI from "openai";

1378const client = new OpenAI();1378const client = new OpenAI();

1379 1379 


1561 1561 

1562 Refactor code1562 Refactor code

1563 1563 

1564```javascript1564```typescript

1565import OpenAI from "openai";1565import OpenAI from "openai";

1566 1566 

1567const openai = new OpenAI();1567const openai = new OpenAI();


1810 1810 

1811 Plan and create a Python project1811 Plan and create a Python project

1812 1812 

1813```javascript1813```typescript

1814import OpenAI from "openai";1814import OpenAI from "openai";

1815 1815 

1816const openai = new OpenAI();1816const openai = new OpenAI();


1985 1985 

1986 Ask questions related to basic scientific research1986 Ask questions related to basic scientific research

1987 1987 

1988```javascript1988```typescript

1989import OpenAI from "openai";1989import OpenAI from "openai";

1990 1990 

1991const openai = new OpenAI();1991const openai = new OpenAI();

Details

36 36 

37## Quickstart37## Quickstart

38 38 

39The Python and JavaScript examples use the beta Responses SDK. For HTTP39The Python and TypeScript examples use the beta Responses SDK. For HTTP

40 requests, use `client.beta.responses` and pass `responses_multi_agent=v1` in40 requests, use `client.beta.responses` and pass `responses_multi_agent=v1` in

41 the `betas` argument. For raw HTTP requests and WebSocket connections, pass41 the `betas` argument. For raw HTTP requests and WebSocket connections, pass

42 `OpenAI-Beta: responses_multi_agent=v1` in the request or connection headers.42 `OpenAI-Beta: responses_multi_agent=v1` in the request or connection headers.


46 46 

47Review a pull request with subagents47Review a pull request with subagents

48 48 

49```javascript49```typescript

50import OpenAI from "openai";50import OpenAI from "openai";

51 51 

52const client = new OpenAI();52const client = new OpenAI();

53 53 

54async function reviewPullRequest(diff) {54async function reviewPullRequest(diff: string) {

55 const response = await client.beta.responses.create({55 const response = await client.beta.responses.create({

56 model: "gpt-6.1-sol",56 model: "gpt-6.1-sol",

57 input:57 input:


186 186 

187Handle HTTP streaming tool calls187Handle HTTP streaming tool calls

188 188 

189```javascript189```typescript

190import OpenAI from "openai";190import OpenAI from "openai";

191 191 

192const client = new OpenAI();192const client = new OpenAI();


196 beta: { estimated_weeks: 8, risk: "low" },196 beta: { estimated_weeks: 8, risk: "low" },

197};197};

198 198 

199const tools = [199const tools: OpenAI.Beta.Responses.BetaTool[] = [

200 {200 {

201 type: "function",201 type: "function",

202 name: "get_proposal",202 name: "get_proposal",


217 },217 },

218];218];

219 219 

220const history = [220const history: (

221 | OpenAI.Beta.Responses.BetaResponseInputItem

222 | OpenAI.Beta.Responses.BetaResponseOutputItem

223)[] = [

221 {224 {

222 role: "user",225 role: "user",

223 content: "Compare proposal alpha and proposal beta.",226 content: "Compare proposal alpha and proposal beta.",

224 },227 },

225];228];

226 229 

227function agentName(item) {230function agentName(item: OpenAI.Beta.Responses.BetaResponseOutputItem) {

228 return item.agent?.agent_name ?? ROOT;231 return item.agent?.agent_name ?? ROOT;

229}232}

230 233 

231function processToolCall(name, argumentsJson) {234function processToolCall(name: string, argumentsJson: string) {

232 if (name !== "get_proposal") {235 if (name !== "get_proposal") {

233 throw new Error(`Unknown tool: ${name}`);236 throw new Error(`Unknown tool: ${name}`);

234 }237 }

235 const { proposal } = JSON.parse(argumentsJson);238 const { proposal }: { proposal: unknown } = JSON.parse(argumentsJson);

236 239 

240 if (proposal !== "alpha" && proposal !== "beta")

241 throw new Error(`Unknown proposal: ${proposal}`);

237 return JSON.stringify(proposals[proposal]);242 return JSON.stringify(proposals[proposal]);

238}243}

239 244 


244 249 

245 const stream = await client.beta.responses.create({250 const stream = await client.beta.responses.create({

246 model: "gpt-6.1-sol",251 model: "gpt-6.1-sol",

247 // Beta output items can be replayed as input on the next request.252 // Replay Beta output unchanged, including agent metadata. The SDK input

248 input: history,253 // union is narrower than the agent_message content returned by the API.

254 input: history as OpenAI.Beta.Responses.BetaResponseInput,

249 tools,255 tools,

250 store: false,256 store: false,

251 multi_agent: {257 multi_agent: {


476 482 

477Inject tool outputs over WebSocket483Inject tool outputs over WebSocket

478 484 

479```javascript485```typescript

480import OpenAI from "openai";486import OpenAI from "openai";

481 487 

482import { ResponsesWS } from "openai/resources/beta/responses/ws";488import { ResponsesWS } from "openai/resources/beta/responses/ws";


486 alpha: { estimated_weeks: 6, risk: "medium" },492 alpha: { estimated_weeks: 6, risk: "medium" },

487 beta: { estimated_weeks: 8, risk: "low" },493 beta: { estimated_weeks: 8, risk: "low" },

488};494};

489const tools = [495const tools: OpenAI.Beta.Responses.BetaTool[] = [

490 {496 {

491 type: "function",497 type: "function",

492 name: "get_proposal",498 name: "get_proposal",


507 },513 },

508];514];

509 515 

510function processToolCall(name, argumentsJson) {516function processToolCall(name: string, argumentsJson: string) {

511 if (name !== "get_proposal") {517 if (name !== "get_proposal") {

512 throw new Error(`Unknown tool: ${name}`);518 throw new Error(`Unknown tool: ${name}`);

513 }519 }

514 const { proposal } = JSON.parse(argumentsJson);520 const { proposal }: { proposal: unknown } = JSON.parse(argumentsJson);

515 521 

522 if (proposal !== "alpha" && proposal !== "beta")

523 throw new Error(`Unknown proposal: ${proposal}`);

516 return JSON.stringify(proposals[proposal]);524 return JSON.stringify(proposals[proposal]);

517}525}

518 526 

519async function runMultiAgent(ws) {527async function runMultiAgent(ws: ResponsesWS) {

520 let previousResponseId;528 let previousResponseId;

521 let pendingInput = [529 let pendingInput: OpenAI.Beta.Responses.BetaResponseInput = [

522 { role: "user", content: process.argv.slice(2).join(" ") },530 { role: "user", content: process.argv.slice(2).join(" ") },

523 ];531 ];

524 532 


599 previousResponseId = completedResponse.id;607 previousResponseId = completedResponse.id;

600 pendingInput = nextInput;608 pendingInput = nextInput;

601 }609 }

610 throw new Error("The response ended without a result.");

602}611}

603 612 

604const ws = new ResponsesWS(client, {613const ws = new ResponsesWS(client, {

Details

16 16 

17Create vector store with files17Create vector store with files

18 18 

19```javascript19```typescript

20import OpenAI from "openai";20import OpenAI from "openai";

21const client = new OpenAI();21const client = new OpenAI();

22 22 


143 143 

144Search query144Search query

145 145 

146```javascript146```typescript

147const userQuery = "What is the return policy?";147const userQuery = "What is the return policy?";

148 148 

149const results = await client.vectorStores.search(vector_store.id, {149const results = await client.vectorStores.search(vector_store.id, {


235 235 

236Search query236Search query

237 237 

238```javascript238```typescript

239const results = await client.vectorStores.search(vector_store.id, {239const results = await client.vectorStores.search(vector_store.id, {

240 query: "How many woodchucks are allowed per passenger?",240 query: "How many woodchucks are allowed per passenger?",

241});241});


553 553 

554 Create vector store554 Create vector store

555 555 

556```javascript556```typescript

557await client.vectorStores.create({557await client.vectorStores.create({

558 name: "Support FAQ",558 name: "Support FAQ",

559 file_ids: ["file_123"],559 file_ids: ["file_123"],


626 626 

627 Retrieve vector store627 Retrieve vector store

628 628 

629```javascript629```typescript

630await client.vectorStores.retrieve("vs_123");630await client.vectorStores.retrieve("vs_123");

631```631```

632 632 


682 682 

683 Update vector store683 Update vector store

684 684 

685```javascript685```typescript

686await client.vectorStores.update("vs_123", {686await client.vectorStores.update("vs_123", {

687 name: "Support FAQ Updated",687 name: "Support FAQ Updated",

688});688});


751 751 

752 Delete vector store752 Delete vector store

753 753 

754```javascript754```typescript

755await client.vectorStores.delete("vs_123");755await client.vectorStores.delete("vs_123");

756```756```

757 757 


807 807 

808 List vector stores808 List vector stores

809 809 

810```javascript810```typescript

811await client.vectorStores.list();811await client.vectorStores.list();

812```812```

813 813 


864 864 

865 Create vector store file865 Create vector store file

866 866 

867```javascript867```typescript

868await client.vectorStores.files.createAndPoll("vs_123", {868await client.vectorStores.files.createAndPoll("vs_123", {

869 file_id: "file_123",869 file_id: "file_123",

870});870});


938 938 

939 Upload vector store file939 Upload vector store file

940 940 

941```javascript941```typescript

942await client.vectorStores.files.uploadAndPoll(942await client.vectorStores.files.uploadAndPoll(

943 "vs_123",943 "vs_123",

944 fs.createReadStream("customer_policies.txt")944 fs.createReadStream("customer_policies.txt")


1044 1044 

1045 Retrieve vector store file1045 Retrieve vector store file

1046 1046 

1047```javascript1047```typescript

1048await client.vectorStores.files.retrieve("file_123", {1048await client.vectorStores.files.retrieve("file_123", {

1049 vector_store_id: "vs_123",1049 vector_store_id: "vs_123",

1050});1050});


1114 1114 

1115 Update vector store file1115 Update vector store file

1116 1116 

1117```javascript1117```typescript

1118await client.vectorStores.files.update("file_123", {1118await client.vectorStores.files.update("file_123", {

1119 vector_store_id: "vs_123",1119 vector_store_id: "vs_123",

1120 attributes: { key: "value" },1120 attributes: { key: "value" },


1197 1197 

1198 Delete vector store file1198 Delete vector store file

1199 1199 

1200```javascript1200```typescript

1201await client.vectorStores.files.delete("file_123", {1201await client.vectorStores.files.delete("file_123", {

1202 vector_store_id: "vs_123",1202 vector_store_id: "vs_123",

1203});1203});


1267 1267 

1268 List vector store files1268 List vector store files

1269 1269 

1270```javascript1270```typescript

1271await client.vectorStores.files.list("vs_123");1271await client.vectorStores.files.list("vs_123");

1272```1272```

1273 1273 


1324 1324 

1325 Batch create operation1325 Batch create operation

1326 1326 

1327```javascript1327```typescript

1328await client.vectorStores.fileBatches.createAndPoll("vs_123", {1328await client.vectorStores.fileBatches.createAndPoll("vs_123", {

1329 files: [1329 files: [

1330 {1330 {


1501 1501 

1502 Batch retrieve operation1502 Batch retrieve operation

1503 1503 

1504```javascript1504```typescript

1505await client.vectorStores.fileBatches.retrieve("vsfb_123", {1505await client.vectorStores.fileBatches.retrieve("vsfb_123", {

1506 vector_store_id: "vs_123",1506 vector_store_id: "vs_123",

1507});1507});


1574 1574 

1575 Batch cancel operation1575 Batch cancel operation

1576 1576 

1577```javascript1577```typescript

1578await client.vectorStores.fileBatches.cancel("vsfb_123", {1578await client.vectorStores.fileBatches.cancel("vsfb_123", {

1579 vector_store_id: "vs_123",1579 vector_store_id: "vs_123",

1580});1580});


1647 1647 

1648 List files in a batch1648 List files in a batch

1649 1649 

1650```javascript1650```typescript

1651await client.vectorStores.fileBatches.listFiles("vsfb_123", {1651await client.vectorStores.fileBatches.listFiles("vsfb_123", {

1652 vector_store_id: "vs_123",1652 vector_store_id: "vs_123",

1653});1653});


1723 1723 

1724Create vector store file with attributes1724Create vector store file with attributes

1725 1725 

1726```javascript1726```typescript

1727await client.vectorStores.files.create("<vector_store_id>", {1727await client.vectorStores.files.create("<vector_store_id>", {

1728 file_id: "file_123",1728 file_id: "file_123",

1729 attributes: {1729 attributes: {


1815 1815 

1816Set expiration policy for vector store1816Set expiration policy for vector store

1817 1817 

1818```javascript1818```typescript

1819await client.vectorStores.update("vs_123", {1819await client.vectorStores.update("vs_123", {

1820 expires_after: {1820 expires_after: {

1821 anchor: "last_active_at",1821 anchor: "last_active_at",


1951 1951 

1952Perform search query to get results1952Perform search query to get results

1953 1953 

1954```javascript1954```typescript

1955import OpenAI from "openai";1955import OpenAI from "openai";

1956 1956 

1957const client = new OpenAI();1957const client = new OpenAI();


2029 2029 

2030Synthesize a response based on results2030Synthesize a response based on results

2031 2031 

2032```javascript2032```typescript

2033const formattedResults = formatResults(results.data);2033const formattedResults = formatResults(results.data);

2034// Join the text content of all results2034// Join the text content of all results

2035const textSources = results.data2035const textSources = results.data


2210 2210 

2211Sample result formatting function2211Sample result formatting function

2212 2212 

2213```javascript2213```typescript

2214function formatResults(results) {2214function formatResults(results: {

2215 data: import("openai/resources/vector-stores").VectorStoreSearchResponse[];

2216}) {

2215 let formattedResults = "";2217 let formattedResults = "";

2216 for (const result of results.data) {2218 for (const result of results.data) {

2217 let formattedResult = `<result file_id='${result.file_id}' file_name='${result.filename}'>`;2219 let formattedResult = `<result file_id='${result.file_id}' file_name='${result.filename}'>`;

Details

64 64 

65Example: Providing a safety identifier65Example: Providing a safety identifier

66 66 

67```javascript67```typescript

68import OpenAI from "openai";68import OpenAI from "openai";

69 69 

70const client = new OpenAI();70const client = new OpenAI();

Details

33 33 

34 Providing a safety identifier with the Responses API34 Providing a safety identifier with the Responses API

35 35 

36```javascript36```typescript

37import OpenAI from "openai";37import OpenAI from "openai";

38 38 

39const client = new OpenAI();39const client = new OpenAI();


136 136 

137 Providing a safety identifier with the Chat Completions API137 Providing a safety identifier with the Chat Completions API

138 138 

139```javascript139```typescript

140import OpenAI from "openai";140import OpenAI from "openai";

141 141 

142const client = new OpenAI();142const client = new OpenAI();

Details

63 63 

64Retrieve a project safety alert64Retrieve a project safety alert

65 65 

66```javascript66```typescript

67// Replace the illustrative IDs and URLs below with your own resource values.67// Replace the illustrative IDs and URLs below with your own resource values.

68import OpenAI from "openai";68import OpenAI from "openai";

69 69 

Details

27 27 

28Transcribe audio28Transcribe audio

29 29 

30```javascript30```typescript

31import fs from "fs";31import fs from "fs";

32import OpenAI from "openai";32import OpenAI from "openai";

33 33 


169 169 

170Add context and language hints170Add context and language hints

171 171 

172```javascript172```typescript

173import fs from "fs";173import fs from "fs";

174import OpenAI from "openai";174import OpenAI from "openai";

175 175 


321 321 

322Diarize a meeting recording322Diarize a meeting recording

323 323 

324```javascript324```typescript

325import fs from "fs";325import fs from "fs";

326import OpenAI from "openai";326import OpenAI from "openai";

327 327 


329 329 

330const agentRef = fs.readFileSync("fixtures/agent.wav").toString("base64");330const agentRef = fs.readFileSync("fixtures/agent.wav").toString("base64");

331 331 

332const transcript = await openai.audio.transcriptions.create({332const transcript = (await openai.audio.transcriptions.create({

333 file: fs.createReadStream("fixtures/meeting.wav"),333 file: fs.createReadStream("fixtures/meeting.wav"),

334 model: "gpt-4o-transcribe-diarize",334 model: "gpt-4o-transcribe-diarize",

335 response_format: "diarized_json",335 response_format: "diarized_json",

336 chunking_strategy: "auto",336 chunking_strategy: "auto",

337 known_speaker_names: ["agent"],337 known_speaker_names: ["agent"],

338 known_speaker_references: ["data:audio/wav;base64," + agentRef],338 known_speaker_references: ["data:audio/wav;base64," + agentRef],

339});339})) as OpenAI.Audio.TranscriptionDiarized;

340 340 

341for (const segment of transcript.segments) {341for (const segment of transcript.segments) {

342 if (!("speaker" in segment)) continue;342 if (!("speaker" in segment)) continue;


557 557 

558Timestamp options558Timestamp options

559 559 

560```javascript560```typescript

561import fs from "fs";561import fs from "fs";

562import OpenAI from "openai";562import OpenAI from "openai";

563 563 


757 757 

758Stream transcriptions758Stream transcriptions

759 759 

760```javascript760```typescript

761import fs from "fs";761import fs from "fs";

762import OpenAI from "openai";762import OpenAI from "openai";

763 763 


925 925 

926Prompt parameter926Prompt parameter

927 927 

928```javascript928```typescript

929import fs from "fs";929import fs from "fs";

930import OpenAI from "openai";930import OpenAI from "openai";

931 931 


1087 1087 

1088Post-processing1088Post-processing

1089 1089 

1090```javascript1090```typescript

1091const systemPrompt = `1091const systemPrompt = `

1092You are a helpful assistant for the company ZyntriQix. Your task is1092You are a helpful assistant for the company ZyntriQix. Your task is

1093to correct any spelling discrepancies in the transcribed text. Make1093to correct any spelling discrepancies in the transcribed text. Make

Details

53 53 

54Update a project plan while it runs54Update a project plan while it runs

55 55 

56```javascript56```typescript

57// Set OPENAI_API_KEY before running this example.57// Set OPENAI_API_KEY before running this example.

58// Install the SDK and WebSocket transport: npm install openai ws58// Install the SDK and WebSocket transport: npm install openai ws

59 59 

Details

11 11 

12To start streaming responses, set `stream=True` in your request to the Responses endpoint:12To start streaming responses, set `stream=True` in your request to the Responses endpoint:

13 13 

14```javascript14```typescript

15import { OpenAI } from "openai";15import { OpenAI } from "openai";

16const client = new OpenAI();16const client = new OpenAI();

17 17 


141 141 

142For a full list of event types, see the [API reference for streaming](https://developers.openai.com/api/reference/resources/responses). Here are a few examples:142For a full list of event types, see the [API reference for streaming](https://developers.openai.com/api/reference/resources/responses). Here are a few examples:

143 143 

144```javascript144```typescript

145for await (const event of stream) {145for await (const event of stream) {

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

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

Details

20 20 

21Getting a structured response21Getting a structured response

22 22 

23```javascript23```typescript

24import OpenAI from "openai";24import OpenAI from "openai";

25import { zodTextFormat } from "openai/helpers/zod";25import { zodTextFormat } from "openai/helpers/zod";

26import { z } from "zod";26import { z } from "zod";


364 364 

365 Structured Outputs for chain-of-thought math tutoring365 Structured Outputs for chain-of-thought math tutoring

366 366 

367```javascript367```typescript

368import OpenAI from "openai";368import OpenAI from "openai";

369import { zodTextFormat } from "openai/helpers/zod";369import { zodTextFormat } from "openai/helpers/zod";

370import { z } from "zod";370import { z } from "zod";


762 762 

763 Extracting data from research papers using Structured Outputs763 Extracting data from research papers using Structured Outputs

764 764 

765```javascript765```typescript

766import OpenAI from "openai";766import OpenAI from "openai";

767import { zodTextFormat } from "openai/helpers/zod";767import { zodTextFormat } from "openai/helpers/zod";

768import { z } from "zod";768import { z } from "zod";


1150 1150 

1151 Generating HTML using Structured Outputs1151 Generating HTML using Structured Outputs

1152 1152 

1153```javascript1153```typescript

1154import OpenAI from "openai";1154import OpenAI from "openai";

1155import { zodTextFormat } from "openai/helpers/zod";1155import { zodTextFormat } from "openai/helpers/zod";

1156import { z } from "zod";1156import { z } from "zod";

1157 1157 

1158const openai = new OpenAI();1158const openai = new OpenAI();

1159 1159 

1160const UI = z.lazy(() =>1160type UIElement = {

1161 type: "div" | "button" | "header" | "section" | "field" | "form";

1162 label: string;

1163 children: UIElement[];

1164 attributes: { name: string; value: string }[];

1165};

1166 

1167const UI: z.ZodType<UIElement> = z.lazy(() =>

1161 z.object({1168 z.object({

1162 type: z.enum(["div", "button", "header", "section", "field", "form"]),1169 type: z.enum(["div", "button", "header", "section", "field", "form"]),

1163 label: z.string(),1170 label: z.string(),


1173 1180 

1174const response = await openai.responses.parse({1181const response = await openai.responses.parse({

1175 model: "gpt-6-astra",1182 model: "gpt-6-astra",

1183 max_output_tokens: 4096,

1176 input: [1184 input: [

1177 {1185 {

1178 role: "system",1186 role: "system",


1180 },1188 },

1181 {1189 {

1182 role: "user",1190 role: "user",

1183 content: "Make a User Profile Form",1191 content:

1192 "Make a small user profile form with exactly three direct children: " +

1193 "a Name field, an Email field, and a Save button. Give each child no children. " +

1194 "Use short labels and at most two short attributes per component.",

1184 },1195 },

1185 ],1196 ],

1186 text: {1197 text: {


1189});1200});

1190 1201 

1191const ui = response.output_parsed;1202const ui = response.output_parsed;

1203if (response.status !== "completed" || !ui)

1204 throw new Error("UI generation did not complete.");

1192```1205```

1193 1206 

1194```python1207```python


1678 1691 

1679 Moderation using Structured Outputs1692 Moderation using Structured Outputs

1680 1693 

1681```javascript1694```typescript

1682import OpenAI from "openai";1695import OpenAI from "openai";

1683import { zodTextFormat } from "openai/helpers/zod";1696import { zodTextFormat } from "openai/helpers/zod";

1684import { z } from "zod";1697import { z } from "zod";


2081 2094 

2082 2095 

2083 2096 

2084```javascript2097```typescript

2085const response = await openai.responses.create({2098const response = await openai.responses.create({

2086 model: "gpt-6-astra",2099 model: "gpt-6-astra",

2087 input: [2100 input: [


2461 2474 

2462 2475 

2463 2476 

2464```javascript2477```typescript

2465try {2478try {

2466 const response = await openai.responses.create({2479 const response = await openai.responses.create({

2467 model: "gpt-6-astra",2480 model: "gpt-6-astra",


2514 2527 

2515 if (2528 if (

2516 response.status === "incomplete" &&2529 response.status === "incomplete" &&

2517 response.incomplete_details.reason === "max_output_tokens"2530 response.incomplete_details?.reason === "max_output_tokens"

2518 ) {2531 ) {

2519 // Handle the case where the model did not return a complete response2532 // Handle the case where the model did not return a complete response

2520 throw new Error("Incomplete response");2533 throw new Error("Incomplete response");


2926 2939 

2927Switch from plain text to a structured crate count2940Switch from plain text to a structured crate count

2928 2941 

2929```javascript2942```typescript

2930import OpenAI from "openai";2943import OpenAI from "openai";

2931import { zodTextFormat } from "openai/helpers/zod";2944import { zodTextFormat } from "openai/helpers/zod";

2932import { z } from "zod";2945import { z } from "zod";


3220 3233 

3221 3234 

3222 3235 

3223```javascript3236```typescript

3224const Step = z.object({3237const Step = z.object({

3225 explanation: z.string(),3238 explanation: z.string(),

3226 output: z.string(),3239 output: z.string(),


3650 3663 

3651 3664 

3652 3665 

3653```javascript3666```typescript

3654import { OpenAI } from "openai";3667import { OpenAI } from "openai";

3655import { zodTextFormat } from "openai/helpers/zod";3668import { zodTextFormat } from "openai/helpers/zod";

3656import { z } from "zod";3669import { z } from "zod";


4037 4050 

4038Note that the root level object of a schema must be an object, and not use `anyOf`. A pattern that appears in Zod (as one example) is using a discriminated union, which produces an `anyOf` at the top level. So code such as the following won't work:4051Note that the root level object of a schema must be an object, and not use `anyOf`. A pattern that appears in Zod (as one example) is using a discriminated union, which produces an `anyOf` at the top level. So code such as the following won't work:

4039 4052 

4040```javascript4053```typescript

4041import { z } from "zod";4054import { z } from "zod";

4042import { zodResponseFormat } from "openai/helpers/zod";4055import { zodResponseFormat } from "openai/helpers/zod";

4043 4056 

4044const BaseResponseSchema = z.object({4057const BaseResponseSchema = z.object({

4045 /* ... */4058 status: z.literal("success"),

4059 data: z.string(),

4046});4060});

4047const UnsuccessfulResponseSchema = z.object({4061const UnsuccessfulResponseSchema = z.object({

4048 /* ... */4062 status: z.literal("error"),

4063 error: z.string(),

4049});4064});

4050 4065 

4051const finalSchema = z.discriminatedUnion("status", [4066const finalSchema = z.discriminatedUnion("status", [


4423 4438 

4424 4439 

4425 4440 

4426```javascript4441```typescript

4427const we_did_not_specify_stop_tokens = true;4442const we_did_not_specify_stop_tokens = true;

4428 4443 

4429try {4444try {


4449 // Check if the conversation was too long for the context window, resulting in incomplete JSON4464 // Check if the conversation was too long for the context window, resulting in incomplete JSON

4450 if (4465 if (

4451 response.status === "incomplete" &&4466 response.status === "incomplete" &&

4452 response.incomplete_details.reason === "max_output_tokens"4467 response.incomplete_details?.reason === "max_output_tokens"

4453 ) {4468 ) {

4454 // your code should handle this error case4469 // your code should handle this error case

4455 }4470 }


4464 // Check if the model's output included restricted content, so the generation of JSON was halted and may be partial4479 // Check if the model's output included restricted content, so the generation of JSON was halted and may be partial

4465 if (4480 if (

4466 response.status === "incomplete" &&4481 response.status === "incomplete" &&

4467 response.incomplete_details.reason === "content_filter"4482 response.incomplete_details?.reason === "content_filter"

4468 ) {4483 ) {

4469 // your code should handle this error case4484 // your code should handle this error case

4470 }4485 }

guides/text.md +4 −4

Details

8 8 

9Generate text from a simple prompt9Generate text from a simple prompt

10 10 

11```javascript11```typescript

12import OpenAI from "openai";12import OpenAI from "openai";

13const client = new OpenAI();13const client = new OpenAI();

14 14 


161 161 

162Because the content generated from a model is non-deterministic, prompting to get your desired output is a mix of art and science. However, you can apply techniques and best practices to get good results consistently.162Because the content generated from a model is non-deterministic, prompting to get your desired output is a mix of art and science. However, you can apply techniques and best practices to get good results consistently.

163 163 

164Some prompt engineering techniques work with every model, like using message roles. But different models might need to be prompted differently to produce the best results. Even different snapshots of models within the same family could produce different results. So as you build more complex applications, we strongly recommend:164Some prompt engineering techniques work with every model, like using message roles. But different models might need to be prompted differently to produce the best results. Even different snapshots of models within the same family could produce different results. As you build more complex applications, we strongly recommend:

165 165 

166- Pinning your production applications to specific [model snapshots](https://developers.openai.com/api/docs/models) (like `gpt-5.5-2026-04-23` for example) to ensure consistent behavior166- Pinning your production applications to specific [model snapshots](https://developers.openai.com/api/docs/models) (like `gpt-5.5-2026-04-23` for example) to ensure consistent behavior

167- Building tests and evaluation suites that measure prompt behavior so you can monitor performance as you iterate, or when you change and upgrade model versions167- Building tests and evaluation suites that measure prompt behavior so you can monitor performance as you iterate, or when you change and upgrade model versions


182 182 

183Generate text with instructions183Generate text with instructions

184 184 

185```javascript185```typescript

186import OpenAI from "openai";186import OpenAI from "openai";

187const client = new OpenAI();187const client = new OpenAI();

188 188 


325 325 

326Generate text with messages using different roles326Generate text with messages using different roles

327 327 

328```javascript328```typescript

329import OpenAI from "openai";329import OpenAI from "openai";

330const client = new OpenAI();330const client = new OpenAI();

331 331 

Details

34 34 

35Generate spoken audio from input text35Generate spoken audio from input text

36 36 

37```javascript37```typescript

38import fs from "fs";38import fs from "fs";

39import path from "path";39import path from "path";

40import OpenAI from "openai";40import OpenAI from "openai";


233 233 

234Stream spoken audio from input text directly to your speakers234Stream spoken audio from input text directly to your speakers

235 235 

236```javascript236```typescript

237import OpenAI from "openai";237import OpenAI from "openai";

238import { playAudio } from "openai/helpers/audio";238import { playAudio } from "openai/helpers/audio";

239 239 

Details

27 27 

28Simple text input28Simple text input

29 29 

30```javascript30```typescript

31import OpenAI from "openai";31import OpenAI from "openai";

32 32 

33const client = new OpenAI();33const client = new OpenAI();


129 129 

130Multi-turn conversation130Multi-turn conversation

131 131 

132```javascript132```typescript

133import OpenAI from "openai";133import OpenAI from "openai";

134 134 

135const client = new OpenAI();135const client = new OpenAI();


289 289 

290Input with system instructions290Input with system instructions

291 291 

292```javascript292```typescript

293import OpenAI from "openai";293import OpenAI from "openai";

294 294 

295const client = new OpenAI();295const client = new OpenAI();


402 402 

403Input with an image403Input with an image

404 404 

405```javascript405```typescript

406import OpenAI from "openai";406import OpenAI from "openai";

407 407 

408const client = new OpenAI();408const client = new OpenAI();


585 585 

586Input with function tools586Input with function tools

587 587 

588```javascript588```typescript

589import OpenAI from "openai";589import OpenAI from "openai";

590 590 

591const client = new OpenAI();591const client = new OpenAI();

guides/tools.md +9 −9

Details

12 12 

13 Include web search results for the model response13 Include web search results for the model response

14 14 

15```javascript15```typescript

16import OpenAI from "openai";16import OpenAI from "openai";

17const client = new OpenAI();17const client = new OpenAI();

18 18 


149 149 

150 Search your files in a response150 Search your files in a response

151 151 

152```javascript152```typescript

153import OpenAI from "openai";153import OpenAI from "openai";

154const openai = new OpenAI();154const openai = new OpenAI();

155 155 


275 275 

276 Load deferred tools at runtime276 Load deferred tools at runtime

277 277 

278```javascript278```typescript

279import OpenAI from "openai";279import OpenAI from "openai";

280 280 

281const client = new OpenAI();281const client = new OpenAI();

282 282 

283const crmNamespace = {283const crmNamespace: OpenAI.Responses.NamespaceTool = {

284 type: "namespace",284 type: "namespace",

285 name: "crm",285 name: "crm",

286 description: "CRM tools for customer lookup and order management.",286 description: "CRM tools for customer lookup and order management.",


542 542 

543 Call your own function543 Call your own function

544 544 

545```javascript545```typescript

546import OpenAI from "openai";546import OpenAI from "openai";

547const client = new OpenAI();547const client = new OpenAI();

548 548 

549const tools = [549const tools: OpenAI.Responses.Tool[] = [

550 {550 {

551 type: "function",551 type: "function",

552 name: "get_weather",552 name: "get_weather",


851 }'851 }'

852```852```

853 853 

854```javascript854```typescript

855import OpenAI from "openai";855import OpenAI from "openai";

856const client = new OpenAI();856const client = new OpenAI();

857 857 


1088 1088 

1089Wrap local logic as a function tool1089Wrap local logic as a function tool

1090 1090 

1091```javascript1091```typescript

1092import { tool } from "@openai/agents";1092import { tool } from "@openai/agents";

1093import { z } from "zod";1093import { z } from "zod";

1094 1094 


1115 1115 

1116Expose a specialist as a tool1116Expose a specialist as a tool

1117 1117 

1118```javascript1118```typescript

1119import { Agent } from "@openai/agents";1119import { Agent } from "@openai/agents";

1120 1120 

1121const summarizer = new Agent({1121const summarizer = new Agent({

Details

44 44 

45Ask the model to plan and emit patches45Ask the model to plan and emit patches

46 46 

47```javascript47```typescript

48import OpenAI from "openai";48import OpenAI from "openai";

49// Application-owned helper; see "Implementing the patch harness" in the guide.49// Application-owned helper; see "Implementing the patch harness" in the guide.

50// This demo only applies exact updates to the two in-memory files below.50// This demo only applies exact updates to the two in-memory files below.


204 204 

205Apply the patch and return results205Apply the patch and return results

206 206 

207```javascript207```typescript

208for (let turn = 0; patchCalls.length > 0; turn++) {208for (let turn = 0; patchCalls.length > 0; turn++) {

209 if (turn === 8) throw new Error("Patch workflow exceeded eight tool turns.");209 if (turn === 8) throw new Error("Patch workflow exceeded eight tool turns.");

210 const results = patchCalls.map((call) => {210 const results = patchCalls.map((call): OpenAI.Responses.ResponseInputItem => {

211 const { success, output } = applyOperation(files, call.operation);211 const { success, output } = applyOperation(files, call.operation);

212 212 

213 return {213 return {


427 427 

428Use the apply patch tool with the Agents SDK428Use the apply patch tool with the Agents SDK

429 429 

430```javascript430```typescript

431import {431import {

432 mkdirSync,432 mkdirSync,

433 realpathSync,433 realpathSync,


437 unlinkSync,437 unlinkSync,

438} from "node:fs";438} from "node:fs";

439import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";439import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";

440import { applyDiff, Agent, run, applyPatchTool } from "@openai/agents";440import {

441 441 applyDiff,

442class WorkspaceEditor {442 Agent,

443 run,

444 applyPatchTool,

445 type Editor,

446 type ApplyPatchResult,

447} from "@openai/agents";

448 

449class WorkspaceEditor implements Editor {

450 root: string;

443 constructor(root = "workspace") {451 constructor(root = "workspace") {

444 mkdirSync(root, { recursive: true });452 mkdirSync(root, { recursive: true });

445 this.root = realpathSync(root);453 this.root = realpathSync(root);

446 }454 }

447 455 

448 path(name) {456 path(name: string) {

449 const target = resolve(this.root, name);457 const target = resolve(this.root, name);

450 const relativePath = relative(this.root, target);458 const relativePath = relative(this.root, target);

451 if (459 if (


466 return target;474 return target;

467 }475 }

468 476 

469 async createFile(operation) {477 async createFile(

478 operation: Parameters<Editor["createFile"]>[0]

479 ): Promise<ApplyPatchResult> {

470 const path = this.path(operation.path);480 const path = this.path(operation.path);

471 const content = applyDiff("", operation.diff, "create");481 const content = applyDiff("", operation.diff, "create");

472 mkdirSync(dirname(path), { recursive: true });482 mkdirSync(dirname(path), { recursive: true });


474 return { status: "completed", output: `Created ${operation.path}` };484 return { status: "completed", output: `Created ${operation.path}` };

475 }485 }

476 486 

477 async updateFile(operation) {487 async updateFile(

488 operation: Parameters<Editor["updateFile"]>[0]

489 ): Promise<ApplyPatchResult> {

478 const path = this.path(operation.path);490 const path = this.path(operation.path);

479 const content = applyDiff(readFileSync(path, "utf8"), operation.diff);491 const content = applyDiff(readFileSync(path, "utf8"), operation.diff);

480 writeFileSync(path, content, "utf8");492 writeFileSync(path, content, "utf8");

481 return { status: "completed", output: `Updated ${operation.path}` };493 return { status: "completed", output: `Updated ${operation.path}` };

482 }494 }

483 495 

484 async deleteFile(operation) {496 async deleteFile(

497 operation: Parameters<Editor["deleteFile"]>[0]

498 ): Promise<ApplyPatchResult> {

485 unlinkSync(this.path(operation.path));499 unlinkSync(this.path(operation.path));

486 return { status: "completed", output: `Deleted ${operation.path}` };500 return { status: "completed", output: `Deleted ${operation.path}` };

487 }501 }

Details

28 }'28 }'

29```29```

30 30 

31```javascript31```typescript

32import OpenAI from "openai";32import OpenAI from "openai";

33const client = new OpenAI();33const client = new OpenAI();

34 34 


190 }'190 }'

191```191```

192 192 

193```javascript193```typescript

194import OpenAI from "openai";194import OpenAI from "openai";

195const client = new OpenAI();195const client = new OpenAI();

196 196 

Details

8 8 

9Connect the API loop to your browser or desktop runtime.9Connect the API loop to your browser or desktop runtime.

10 10 

11```javascript11```typescript

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

13import OpenAI from "openai";13import OpenAI from "openai";

14 14 

15async function runComputerUse(endpoint, prompt, model = "gpt-6-astra") {15async function runComputerUse(

16 endpoint: string,

17 prompt: string,

18 model = "gpt-6-astra"

19) {

16 const client = new OpenAI();20 const client = new OpenAI();

17 const sessionId = randomUUID();21 const sessionId = randomUUID();

18 22 

19 const tools = [23 const tools: OpenAI.Responses.Tool[] = [

20 {24 {

21 type: "function",25 type: "function",

22 name: "exec_js",26 name: "exec_js",


36 },40 },

37 ];41 ];

38 42 

39 let nextInput = [{ role: "user", content: prompt }];43 let nextInput: OpenAI.Responses.ResponseInput = [

40 let previousResponseId;44 { role: "user", content: prompt },

45 ];

46 let previousResponseId: string | undefined;

41 47 

42 for (let turn = 0; turn < 20; turn++) {48 for (let turn = 0; turn < 20; turn++) {

43 const response = await client.responses.create({49 const response: OpenAI.Responses.Response = await client.responses.create({

44 model,50 model,

45 tools,51 tools,

46 input: nextInput,52 input: nextInput,


517 523 

518Use the computer tool for structured mouse and keyboard actions.524Use the computer tool for structured mouse and keyboard actions.

519 525 

520```javascript526```typescript

521import OpenAI from "openai";527import OpenAI from "openai";

522 528 

523const client = new OpenAI();529const client = new OpenAI();


607 613 

608Continue the conversation with the updated screen.614Continue the conversation with the updated screen.

609 615 

610```javascript616```typescript

611import OpenAI from "openai";617import OpenAI from "openai";

612 618 

613const client = new OpenAI();619const client = new OpenAI();

614 620 

615async function sendComputerScreenshot(response, callId, screenshotBase64) {621async function sendComputerScreenshot(

622 response: OpenAI.Responses.Response,

623 callId: string,

624 screenshotBase64: string

625) {

616 const output = {626 const output = {

617 type: "computer_screenshot",627 type: "computer_screenshot" as const,

618 image_url: `data:image/png;base64,${screenshotBase64}`,628 image_url: `data:image/png;base64,${screenshotBase64}`,

619 detail: "original",629 detail: "original",

620 };630 };


811 821 

812The model sees a screenshot of a fictional parcel pickup page and clicks to reveal the pickup details. The driver allows only screenshots and a left click on that control. It blocks page requests and closes the browser when the run ends. The script makes at most six Responses requests and checks the page before reporting success. Your project needs access to a model that supports the computer tool.822The model sees a screenshot of a fictional parcel pickup page and clicks to reveal the pickup details. The driver allows only screenshots and a left click on that control. It blocks page requests and closes the browser when the run ends. The script makes at most six Responses requests and checks the page before reporting success. Your project needs access to a model that supports the computer tool.

813 823 

814Save the matching example as `pickup.py` or `pickup.mjs`:824Save the matching example as `pickup.py` or `pickup.mts`:

815 825 

816Reveal pickup details using computer actions826Reveal pickup details using computer actions

817 827 

818```javascript828```typescript

819import OpenAI, { ComputerToolset } from "openai";829import OpenAI, { ComputerToolset } from "openai";

820import { chromium } from "playwright";830import { chromium, type Page } from "playwright";

821 831 

822class PickupDriver {832class PickupDriver {

823 constructor(page) {833 page: Page;

834 

835 constructor(page: Page) {

824 this.page = page;836 this.page = page;

825 }837 }

826 838 

827 async screenshot() {839 async screenshot(): Promise<OpenAI.Responses.ResponseComputerToolCallOutputScreenshot> {

828 const image = await this.page.screenshot({ type: "png" });840 const image = await this.page.screenshot({ type: "png" });

829 return {841 return {

830 type: "computer_screenshot",842 type: "computer_screenshot",


832 };844 };

833 }845 }

834 846 

835 async allowed(action) {847 async allowed(action: OpenAI.Responses.ComputerAction) {

836 if (action.type === "screenshot") return true;848 if (action.type === "screenshot") return true;

837 if (849 if (

838 action.type !== "click" ||850 action.type !== "click" ||


850 );862 );

851 }863 }

852 864 

853 async click(action) {865 async click(action: OpenAI.Responses.ComputerAction.Click) {

854 // The page may have changed after approval, so bind the click again.866 // The page may have changed after approval, so bind the click again.

855 if (!(await this.allowed(action)))867 if (!(await this.allowed(action)))

856 throw new Error("Pickup details moved or the click is not allowed.");868 throw new Error("Pickup details moved or the click is not allowed.");

857 await this.page.mouse.click(action.x, action.y);869 await this.page.mouse.click(action.x, action.y);

858 }870 }

859 871 

860 refuse(action) {872 refuse(action: OpenAI.Responses.ComputerAction) {

861 throw new Error(`This exercise does not allow ${action.type}.`);873 throw new Error(`This exercise does not allow ${action.type}.`);

862 }874 }

863 875 


1005```1017```

1006 1018 

1007 1019 

1008Run `.venv/bin/python pickup.py` or `node pickup.mjs`. On success, the script prints `Verified pickup details: Locker 18. Pickup code: 6249.`, followed by the model's answer. Pending API safety checks stop this sample; add a human approval callback only when your application can handle them.1020Run `.venv/bin/python pickup.py` or `node --experimental-strip-types pickup.mts`. On success, the script prints `Verified pickup details: Locker 18. Pickup code: 6249.`, followed by the model's answer. Pending API safety checks stop this sample; add a human approval callback only when your application can handle them.

1009 1021 

1010 1022

1011 1023 


1014 1026 

1015The model types a name into a visitor badge form and clicks **Create badge**. The driver exposes only page reading, typing, and clicking. Its confirmation callback permits only this form's controls and the name Mira. The script verifies the page result before reporting success.1027The model types a name into a visitor badge form and clicks **Create badge**. The driver exposes only page reading, typing, and clicking. Its confirmation callback permits only this form's controls and the name Mira. The script verifies the page result before reporting success.

1016 1028 

1017Save the matching example as `badge.py` or `badge.mjs`:1029Save the matching example as `badge.py` or `badge.mts`:

1018 1030 

1019Create a visitor badge in a local browser1031Create a visitor badge in a local browser

1020 1032 

1021```javascript1033```typescript

1022import OpenAI from "openai";1034import OpenAI from "openai";

1023import { BrowserToolset } from "openai/helpers/browser";1035import {

1036 BrowserToolset,

1037 type BrowserArguments,

1038 type BrowserConfirmContext,

1039 type BrowserReadV1,

1040} from "openai/helpers/browser";

1024import { ResponsesToolRunner } from "openai/helpers/responses-tool-runner";1041import { ResponsesToolRunner } from "openai/helpers/responses-tool-runner";

1025import { chromium } from "playwright";1042import { chromium, type Page } from "playwright";

1026 1043 

1027class BadgeForm {1044class BadgeForm {

1028 constructor(page) {1045 page: Page;

1046 

1047 constructor(page: Page) {

1029 this.page = page;1048 this.page = page;

1030 }1049 }

1031 1050 


1042 };1061 };

1043 }1062 }

1044 1063 

1045 async read_page(_args) {1064 async read_page(

1065 _args: BrowserArguments<"read_page">

1066 ): Promise<BrowserReadV1> {

1046 return {1067 return {

1047 version: 1,1068 version: 1,

1048 text: await this.page.locator("body").innerText(),1069 text: await this.page.locator("body").innerText(),


1054 };1075 };

1055 }1076 }

1056 1077 

1057 async type(args) {1078 async type(args: BrowserArguments<"type">) {

1058 await this.page.locator("#name").fill(args.text);1079 await this.page.locator("#name").fill(args.text);

1059 }1080 }

1060 1081 

1061 async click(_args) {1082 async click(_args: BrowserArguments<"click">) {

1062 await this.page.locator("#save").click();1083 await this.page.locator("#save").click();

1063 }1084 }

1064 1085 

1065 async confirm({ member, arguments: args }) {1086 async confirm({ member, arguments: args }: BrowserConfirmContext) {

1066 if (1087 if (

1067 this.page.url() !== "about:blank" ||1088 this.page.url() !== "about:blank" ||

1068 (args.tab_id !== null && args.tab_id !== "badge")1089 (args.tab_id !== null && args.tab_id !== "badge")


1213```1234```

1214 1235 

1215 1236 

1216Run `.venv/bin/python badge.py` or `node badge.mjs`. On success, the script prints `Badge ready: Mira`, followed by the model's answer.1237Run `.venv/bin/python badge.py` or `node --experimental-strip-types badge.mts`. On success, the script prints `Badge ready: Mira`, followed by the model's answer.

1217 1238 

1218 1239 

1219 1240 


1376 1397

1377 1398 

1378 1399

1379JavaScript1400TypeScript

1380 1401 

1381 Run computer use with code execution1402 Run computer use with code execution

1382 1403 

1383```javascript1404```typescript

1384import { randomUUID } from "node:crypto";1405import { randomUUID } from "node:crypto";

1385import OpenAI from "openai";1406import OpenAI from "openai";

1386 1407 

1387async function runComputerUse(endpoint, prompt, model = "gpt-6-astra") {1408async function runComputerUse(

1409 endpoint: string,

1410 prompt: string,

1411 model = "gpt-6-astra"

1412) {

1388 const client = new OpenAI();1413 const client = new OpenAI();

1389 const sessionId = randomUUID();1414 const sessionId = randomUUID();

1390 1415 

1391 const tools = [1416 const tools: OpenAI.Responses.Tool[] = [

1392 {1417 {

1393 type: "function",1418 type: "function",

1394 name: "exec_js",1419 name: "exec_js",


1408 },1433 },

1409 ];1434 ];

1410 1435 

1411 let nextInput = [{ role: "user", content: prompt }];1436 let nextInput: OpenAI.Responses.ResponseInput = [

1412 let previousResponseId;1437 { role: "user", content: prompt },

1438 ];

1439 let previousResponseId: string | undefined;

1413 1440 

1414 for (let turn = 0; turn < 20; turn++) {1441 for (let turn = 0; turn < 20; turn++) {

1415 const response = await client.responses.create({1442 const response: OpenAI.Responses.Response = await client.responses.create({

1416 model,1443 model,

1417 tools,1444 tools,

1418 input: nextInput,1445 input: nextInput,


1654 1681 

1655Send a computer request1682Send a computer request

1656 1683 

1657```javascript1684```typescript

1658import OpenAI from "openai";1685import OpenAI from "openai";

1659 1686 

1660const client = new OpenAI();1687const client = new OpenAI();


1789 1816 

1790Send the updated screenshot1817Send the updated screenshot

1791 1818 

1792```javascript1819```typescript

1793import OpenAI from "openai";1820import OpenAI from "openai";

1794 1821 

1795const client = new OpenAI();1822const client = new OpenAI();

1796 1823 

1797async function sendComputerScreenshot(response, callId, screenshotBase64) {1824async function sendComputerScreenshot(

1825 response: OpenAI.Responses.Response,

1826 callId: string,

1827 screenshotBase64: string

1828) {

1798 const output = {1829 const output = {

1799 type: "computer_screenshot",1830 type: "computer_screenshot" as const,

1800 image_url: `data:image/png;base64,${screenshotBase64}`,1831 image_url: `data:image/png;base64,${screenshotBase64}`,

1801 detail: "original",1832 detail: "original",

1802 };1833 };

Details

117 117 

118On Windows, use `py -3` instead of `python3` and `.venv\Scripts\python.exe` instead of `.venv/bin/python`.118On Windows, use `py -3` instead of `python3` and `.venv\Scripts\python.exe` instead of `.venv/bin/python`.

119 119 

120Save the matching sample as `dispatch.py` or `dispatch.mjs` in the same directory.120Save the matching sample as `dispatch.py` or `dispatch.mts` in the same directory.

121 121 

122Write and verify a dispatch note122Write and verify a dispatch note

123 123 

124```javascript124```typescript

125import { execFile } from "node:child_process";125import { execFile } from "node:child_process";

126import { promisify } from "node:util";126import { promisify } from "node:util";

127import { setTimeout as delay } from "node:timers/promises";127import { setTimeout as delay } from "node:timers/promises";


130const note = "Dispatch #1042: ready for pickup.";130const note = "Dispatch #1042: ready for pickup.";

131const exec = promisify(execFile);131const exec = promisify(execFile);

132 132 

133async function desktop(...args) {133async function desktop(...args: string[]) {

134 const { stdout } = await exec(134 const { stdout } = await exec(

135 "docker",135 "docker",

136 ["exec", "cua-visual-desktop", ...args],136 ["exec", "cua-visual-desktop", ...args],


144}144}

145 145 

146class EditorDriver {146class EditorDriver {

147 async screenshot() {147 async screenshot(): Promise<OpenAI.Responses.ResponseComputerToolCallOutputScreenshot> {

148 const image = await desktop("import", "-window", "root", "png:-");148 const image = await desktop("import", "-window", "root", "png:-");

149 return {149 return {

150 type: "computer_screenshot",150 type: "computer_screenshot",


165 await desktop("xdotool", "windowactivate", "--sync", window);165 await desktop("xdotool", "windowactivate", "--sync", window);

166 }166 }

167 167 

168 async type(action) {168 async type(action: { text: string }) {

169 if (action.text !== note)169 if (action.text !== note)

170 throw new Error("Only the dispatch note is allowed.");170 throw new Error("Only the dispatch note is allowed.");

171 await this.focusEditor();171 await this.focusEditor();


180 );180 );

181 }181 }

182 182 

183 async keypress(action) {183 async keypress(action: { keys: string[] }) {

184 const keys = action.keys.map((key) => key.toUpperCase()).join("+");184 const keys = action.keys.map((key: string) => key.toUpperCase()).join("+");

185 if (keys !== "CTRL+A" && keys !== "CTRL+S") {185 if (keys !== "CTRL+A" && keys !== "CTRL+S") {

186 throw new Error(186 throw new Error(

187 `Only Select All and Save are allowed; received ${JSON.stringify(action.keys)}.`187 `Only Select All and Save are allowed; received ${JSON.stringify(action.keys)}.`


191 await desktop("xdotool", "key", "--clearmodifiers", keys.toLowerCase());191 await desktop("xdotool", "key", "--clearmodifiers", keys.toLowerCase());

192 }192 }

193 193 

194 refuse(action) {194 refuse(action: OpenAI.Responses.ComputerAction) {

195 throw new Error(`This exercise does not allow ${action.type}.`);195 throw new Error(`This exercise does not allow ${action.type}.`);

196 }196 }

197 197 


366```bash366```bash

367.venv/bin/python dispatch.py367.venv/bin/python dispatch.py

368# Or:368# Or:

369node dispatch.mjs369node --experimental-strip-types dispatch.mts

370```370```

371 371 

372The SDK selects the editor's text, types a fictional note, saves it, and captures the desktop. It independently reads the guest file and prints `Verified: Dispatch #1042: ready for pickup.` The text should also appear in the viewer. The driver focuses the editor before every action and refuses inputs beyond the fixed note, Select All, and Save. Wait for the command to finish before typing in the viewer again.372The SDK selects the editor's text, types a fictional note, saves it, and captures the desktop. It independently reads the guest file and prints `Verified: Dispatch #1042: ready for pickup.` The text should also appear in the viewer. The driver focuses the editor before every action and refuses inputs beyond the fixed note, Select All, and Save. Wait for the command to finish before typing in the viewer again.


382```bash382```bash

383.venv/bin/python dispatch.py --live383.venv/bin/python dispatch.py --live

384# Or:384# Or:

385node dispatch.mjs --live385node --experimental-strip-types dispatch.mts --live

386```386```

387 387 

388This run uses at most six Responses requests and verifies the file in the same way. It stops if the model requests a safety check or an input this driver does not support. API usage is billed to your project. Only the host SDK reads the API key; screenshots and prompts go to OpenAI.388This run uses at most six Responses requests and verifies the file in the same way. It stops if the model requests a safety check or an input this driver does not support. API usage is billed to your project. Only the host SDK reads the API key; screenshots and prompts go to OpenAI.


430 430 

431Start a browser instance431Start a browser instance

432 432 

433```javascript433```typescript

434import { chromium } from "playwright";434import { chromium } from "playwright";

435 435 

436const browser = await chromium.launch({436const browser = await chromium.launch({


538 538 

539Execute commands on the container539Execute commands on the container

540 540 

541```javascript541```typescript

542import { execFile } from "node:child_process";542import { execFile } from "node:child_process";

543import { promisify } from "node:util";543import { promisify } from "node:util";

544 544 

545const execFileAsync = promisify(execFile);545const execFileAsync = promisify(execFile);

546 546 

547async function dockerExec(547async function dockerExec(

548 containerName,548 containerName: string,

549 executable,549 executable: string,

550 args = [],550 args: Array<string | number> = [],

551 { decode = true, env = {} } = {}551 { decode = true, env = {} } = {}

552) {552) {

553 const environmentArgs = Object.entries(env).flatMap(([name, value]) => [553 const environmentArgs = Object.entries(env).flatMap(([name, value]) => [


656 656 

657 Normalization helpers657 Normalization helpers

658 658 

659```javascript659```typescript

660// Map model-emitted key names to the names Playwright expects.660// Map model-emitted key names to the names Playwright expects.

661const normalizeKey = (key) => {661const normalizeKey = (key: string) => {

662 switch (key) {662 switch (key) {

663 case "ENTER":663 case "ENTER":

664 case "RETURN":664 case "RETURN":


714 714 

715// Translate API button names to Playwright's supported button names.715// Translate API button names to Playwright's supported button names.

716const normalizePlaywrightButton = (button = "left") => {716const normalizePlaywrightButton = (button = "left") => {

717 const buttons = {717 const buttons: Partial<Record<string, "left" | "right" | "middle">> = {

718 left: "left",718 left: "left",

719 right: "right",719 right: "right",

720 wheel: "middle",720 wheel: "middle",


729};729};

730 730 

731// Accept drag paths as either [x, y] pairs or {x, y} objects.731// Accept drag paths as either [x, y] pairs or {x, y} objects.

732const normalizeDragPath = (path) => {732const normalizeDragPath = (

733 path: Array<[number, number] | { x: number; y: number }>

734) => {

733 if (!Array.isArray(path)) {735 if (!Array.isArray(path)) {

734 throw new Error("drag action requires a path array");736 throw new Error("drag action requires a path array");

735 }737 }


814 816 

815 Normalization helpers817 Normalization helpers

816 818 

817```javascript819```typescript

818// Map model-emitted key names to the names xdotool expects.820// Map model-emitted key names to the names xdotool expects.

819const normalizeXdotoolKey = (key) => {821const normalizeXdotoolKey = (key: string) => {

820 switch (key) {822 switch (key) {

821 case "ENTER":823 case "ENTER":

822 case "RETURN":824 case "RETURN":


872 874 

873// Translate API button names to X11 button numbers.875// Translate API button names to X11 button numbers.

874const normalizeXdotoolButton = (button = "left") => {876const normalizeXdotoolButton = (button = "left") => {

875 const buttons = {877 const buttons: Partial<Record<string, number>> = {

876 left: 1,878 left: 1,

877 wheel: 2,879 wheel: 2,

878 right: 3,880 right: 3,


887};889};

888 890 

889// Translate API scroll deltas to vertical and horizontal X11 wheel clicks.891// Translate API scroll deltas to vertical and horizontal X11 wheel clicks.

890const getXdotoolScrollButtons = (scrollX, scrollY) => {892const getXdotoolScrollButtons = (scrollX: number, scrollY: number) => {

891 const scrollButtons = [];893 const scrollButtons: number[] = [];

892 const appendClicks = (delta, negativeButton, positiveButton) => {894 const appendClicks = (

895 delta: number,

896 negativeButton: number,

897 positiveButton: number

898 ) => {

893 if (!delta) {899 if (!delta) {

894 return;900 return;

895 }901 }


904};910};

905 911 

906// Accept drag paths as either [x, y] pairs or {x, y} objects.912// Accept drag paths as either [x, y] pairs or {x, y} objects.

907const normalizeDragPath = (path) => {913const normalizeDragPath = (

914 path: Array<[number, number] | { x: number; y: number }>

915) => {

908 if (!Array.isArray(path)) {916 if (!Array.isArray(path)) {

909 throw new Error("drag action requires a path array");917 throw new Error("drag action requires a path array");

910 }918 }


1008 1016 

1009 Execute Computer use actions1017 Execute Computer use actions

1010 1018 

1011```javascript1019```typescript

1020import type { Page } from "playwright";

1021import type { ComputerAction } from "openai/resources/responses/responses";

1022 

1012// Reuse normalizeKey from the helper above.1023// Reuse normalizeKey from the helper above.

1013// Reuse normalizePlaywrightButton from the helper above.1024// Reuse normalizePlaywrightButton from the helper above.

1014// Reuse normalizeDragPath from the helper above.1025// Reuse normalizeDragPath from the helper above.

1015 1026 

1016function rejectModifiers(action) {1027function rejectModifiers(action: ComputerAction) {

1017 if (action.keys?.length) {1028 if ("keys" in action && action.keys?.length) {

1018 throw new Error(1029 throw new Error(

1019 "This handler does not support modifier keys. Use the modifier-aware handler below."1030 "This handler does not support modifier keys. Use the modifier-aware handler below."

1020 );1031 );

1021 }1032 }

1022}1033}

1023 1034 

1024async function handleComputerActions(page, actions) {1035async function handleComputerActions(page: Page, actions: ComputerAction[]) {

1025 for (const action of actions) {1036 for (const action of actions) {

1026 switch (action.type) {1037 switch (action.type) {

1027 case "click": {1038 case "click": {


1071 case "screenshot":1082 case "screenshot":

1072 break;1083 break;

1073 default:1084 default:

1074 throw new Error(`Unsupported action: ${action.type}`);1085 throw new Error("Unsupported computer action");

1075 }1086 }

1076 }1087 }

1077}1088}


1151 1162 

1152 Execute Computer use actions1163 Execute Computer use actions

1153 1164 

1154```javascript1165```typescript

1166import type { ComputerAction } from "openai/resources/responses/responses";

1167 

1155// Reuse normalizeXdotoolKey from the helper above.1168// Reuse normalizeXdotoolKey from the helper above.

1156// Reuse normalizeXdotoolButton and getXdotoolScrollButtons from the helper above.1169// Reuse normalizeXdotoolButton and getXdotoolScrollButtons from the helper above.

1157// Reuse normalizeDragPath from the helper above.1170// Reuse normalizeDragPath from the helper above.

1158 1171 

1159function rejectModifiers(action) {1172function rejectModifiers(action: ComputerAction) {

1160 if (action.keys?.length) {1173 if ("keys" in action && action.keys?.length) {

1161 throw new Error(1174 throw new Error(

1162 "This handler does not support modifier keys. Use the modifier-aware handler below."1175 "This handler does not support modifier keys. Use the modifier-aware handler below."

1163 );1176 );

1164 }1177 }

1165}1178}

1166 1179 

1167async function handleComputerActions(vm, actions) {1180async function handleComputerActions(

1181 vm: { containerName: string; display: string },

1182 actions: ComputerAction[]

1183) {

1168 for (const action of actions) {1184 for (const action of actions) {

1169 switch (action.type) {1185 switch (action.type) {

1170 case "click": {1186 case "click": {


1261 case "screenshot":1277 case "screenshot":

1262 break;1278 break;

1263 default:1279 default:

1264 throw new Error(`Unsupported action: ${action.type}`);1280 throw new Error("Unsupported computer action");

1265 }1281 }

1266 }1282 }

1267}1283}


1424 1440 

1425 Execute modifier-assisted Computer use actions1441 Execute modifier-assisted Computer use actions

1426 1442 

1427```javascript1443```typescript

1444import type { Page } from "playwright";

1445import type { ComputerAction } from "openai/resources/responses/responses";

1446 

1428// Reuse normalizeKey from the helper above.1447// Reuse normalizeKey from the helper above.

1429// Reuse normalizePlaywrightButton from the helper above.1448// Reuse normalizePlaywrightButton from the helper above.

1430// Reuse normalizeDragPath from the helper above.1449// Reuse normalizeDragPath from the helper above.

1431 1450 

1432async function withModifiers(page, keys, callback) {1451async function withModifiers(

1452 page: Page,

1453 keys: string[] | null | undefined,

1454 callback: () => Promise<void>

1455) {

1433 const normalizedKeys = (keys ?? []).map(normalizeKey);1456 const normalizedKeys = (keys ?? []).map(normalizeKey);

1434 const pressedKeys = [];1457 const pressedKeys = [];

1435 1458 


1447 }1470 }

1448}1471}

1449 1472 

1450async function handleComputerActions(page, actions) {1473async function handleComputerActions(page: Page, actions: ComputerAction[]) {

1451 for (const action of actions) {1474 for (const action of actions) {

1452 switch (action.type) {1475 switch (action.type) {

1453 case "click":1476 case "click":


1501 case "screenshot":1524 case "screenshot":

1502 break;1525 break;

1503 default:1526 default:

1504 throw new Error(`Unsupported action: ${action.type}`);1527 throw new Error("Unsupported computer action");

1505 }1528 }

1506 }1529 }

1507}1530}


1609 1632 

1610 Execute modifier-assisted Computer use actions1633 Execute modifier-assisted Computer use actions

1611 1634 

1612```javascript1635```typescript

1636import type { ComputerAction } from "openai/resources/responses/responses";

1637 

1613// Reuse normalizeXdotoolKey from the helper above.1638// Reuse normalizeXdotoolKey from the helper above.

1614// Reuse normalizeXdotoolButton and getXdotoolScrollButtons from the helper above.1639// Reuse normalizeXdotoolButton and getXdotoolScrollButtons from the helper above.

1615// Reuse normalizeDragPath from the helper above.1640// Reuse normalizeDragPath from the helper above.

1616 1641 

1617async function withModifiers(vm, keys, callback) {1642async function withModifiers(

1643 vm: { containerName: string; display: string },

1644 keys: string[] | null | undefined,

1645 callback: () => Promise<void>

1646) {

1618 const normalizedKeys = (keys ?? []).map(normalizeXdotoolKey);1647 const normalizedKeys = (keys ?? []).map(normalizeXdotoolKey);

1619 const pressedKeys = [];1648 const pressedKeys = [];

1620 1649 


1636 }1665 }

1637}1666}

1638 1667 

1639async function handleComputerActions(vm, actions) {1668async function handleComputerActions(

1669 vm: { containerName: string; display: string },

1670 actions: ComputerAction[]

1671) {

1640 for (const action of actions) {1672 for (const action of actions) {

1641 switch (action.type) {1673 switch (action.type) {

1642 case "click": {1674 case "click": {


1739 case "screenshot":1771 case "screenshot":

1740 break;1772 break;

1741 default:1773 default:

1742 throw new Error(`Unsupported action: ${action.type}`);1774 throw new Error("Unsupported computer action");

1743 }1775 }

1744 }1776 }

1745}1777}


1907 1939 

1908Repeat the Computer use loop1940Repeat the Computer use loop

1909 1941 

1910```javascript1942```typescript

1911import OpenAI from "openai";1943import OpenAI from "openai";

1912 1944 

1913const client = new OpenAI();1945const client = new OpenAI();

1914 1946 

1915async function computerUseLoop(target, response) {1947async function computerUseLoop(

1948 target: Parameters<typeof handleComputerActions>[0],

1949 response: OpenAI.Responses.Response

1950) {

1916 while (true) {1951 while (true) {

1917 const computerCall = response.output.find(1952 const computerCall = response.output.find(

1918 (item) => item.type === "computer_call"1953 (item) => item.type === "computer_call"


1920 if (!computerCall) {1955 if (!computerCall) {

1921 return response;1956 return response;

1922 }1957 }

1958 if (!computerCall.actions) {

1959 throw new Error("Expected batched computer actions.");

1960 }

1923 1961 

1924 await handleComputerActions(target, computerCall.actions);1962 await handleComputerActions(target, computerCall.actions);

1925 1963 

1926 const screenshot = await captureScreenshot(target);1964 const screenshot = await captureScreenshot(target);

1927 const screenshotBase64 = Buffer.from(screenshot).toString("base64");1965 const screenshotBase64 = Buffer.from(screenshot).toString("base64");

1928 const output = {1966 const output = {

1929 type: "computer_screenshot",1967 type: "computer_screenshot" as const,

1930 image_url: `data:image/png;base64,${screenshotBase64}`,1968 image_url: `data:image/png;base64,${screenshotBase64}`,

1931 detail: "original",1969 detail: "original",

1932 };1970 };


2261 2299 

2262 Capture a screenshot2300 Capture a screenshot

2263 2301 

2264```javascript2302```typescript

2265async function captureScreenshot(page) {2303import type { Page } from "playwright";

2304 

2305async function captureScreenshot(page: Page) {

2266 return await page.screenshot({ type: "png" });2306 return await page.screenshot({ type: "png" });

2267}2307}

2268```2308```


2281 2321 

2282 Capture a screenshot2322 Capture a screenshot

2283 2323 

2284```javascript2324```typescript

2285async function captureScreenshot(vm) {2325async function captureScreenshot(vm: {

2326 containerName: string;

2327 display: string;

2328}) {

2286 return await dockerExec(2329 return await dockerExec(

2287 vm.containerName,2330 vm.containerName,

2288 "import",2331 "import",


2389 2432 

2390Connect the API client to your execution service2433Connect the API client to your execution service

2391 2434 

2392```javascript2435```typescript

2393import readline from "node:readline/promises";2436import readline from "node:readline/promises";

2394import { z } from "zod";2437import { z } from "zod";

2395 2438 


2406 )2449 )

2407 .nonempty();2450 .nonempty();

2408 2451 

2409async function executeInSandbox(code, sessionId, endpoint) {2452async function executeInSandbox(

2453 code: string,

2454 sessionId: string,

2455 endpoint: string

2456): Promise<OpenAI.Responses.ResponseFunctionCallOutputItemList> {

2410 console.log(code);2457 console.log(code);

2411 const terminal = readline.createInterface({2458 const terminal = readline.createInterface({

2412 input: process.stdin,2459 input: process.stdin,


2700```2747```

2701 2748 

2702 2749 

2703Python, JavaScript, Ruby, and Go have complete [API loop examples](https://developers.openai.com/api/docs/guides/tools-computer-use#connect-your-own-runtime) for this execution-service contract. Use `run_computer_use` in Python or Ruby, or `runComputerUse` in JavaScript or Go, with your endpoint and task. The Go example also takes a context, SDK client, terminal scanner, and output writer; use its included adapter to preserve those inputs across calls. The loop preserves the runtime session and uses `previous_response_id` to continue the model conversation. It stops after 20 responses if the task has not finished.2750Python, TypeScript, Ruby, and Go have complete [API loop examples](https://developers.openai.com/api/docs/guides/tools-computer-use#connect-your-own-runtime) for this execution-service contract. Use `run_computer_use` in Python or Ruby, or `runComputerUse` in TypeScript or Go, with your endpoint and task. The Go example also takes a context, SDK client, terminal scanner, and output writer; use its included adapter to preserve those inputs across calls. The loop preserves the runtime session and uses `previous_response_id` to continue the model conversation. It stops after 20 responses if the task has not finished.

2704 2751 

2705This adapter asks for approval before every generated script as a conservative demonstration. A production runtime must enforce the action-specific rules in [Handle user confirmation and consent](#handle-user-confirmation-and-consent). Removing the prompt does not supply those controls.2752This adapter asks for approval before every generated script as a conservative demonstration. A production runtime must enforce the action-specific rules in [Handle user confirmation and consent](#handle-user-confirmation-and-consent). Removing the prompt does not supply those controls.

2706 2753 


2856 2903 

2857Legacy preview request2904Legacy preview request

2858 2905 

2859```javascript2906```typescript

2860import OpenAI from "openai";2907import OpenAI from "openai";

2861 2908 

2862const client = new OpenAI();2909const client = new OpenAI();

Details

41 }'41 }'

42```42```

43 43 

44```javascript44```typescript

45import OpenAI from "openai";45import OpenAI from "openai";

46const client = new OpenAI();46const client = new OpenAI();

47 47 


329 }'329 }'

330```330```

331 331 

332```javascript332```typescript

333import OpenAI from "openai";333import OpenAI from "openai";

334const client = new OpenAI();334const client = new OpenAI();

335 335 


545 }'545 }'

546```546```

547 547 

548```javascript548```typescript

549import OpenAI from "openai";549import OpenAI from "openai";

550const client = new OpenAI();550const client = new OpenAI();

551 551 


774 }'774 }'

775```775```

776 776 

777```javascript777```typescript

778import OpenAI from "openai";778import OpenAI from "openai";

779const client = new OpenAI();779const client = new OpenAI();

780 780 


969 }'969 }'

970```970```

971 971 

972```javascript972```typescript

973import OpenAI from "openai";973import OpenAI from "openai";

974const client = new OpenAI();974const client = new OpenAI();

975 975 


1160 }'1160 }'

1161```1161```

1162 1162 

1163```javascript1163```typescript

1164import OpenAI from "openai";1164import OpenAI from "openai";

1165const client = new OpenAI();1165const client = new OpenAI();

1166 1166 


1363 }'1363 }'

1364```1364```

1365 1365 

1366```javascript1366```typescript

1367import OpenAI from "openai";1367import OpenAI from "openai";

1368const client = new OpenAI();1368const client = new OpenAI();

1369 1369 

Details

26 26 

27Generate an image27Generate an image

28 28 

29```javascript29```typescript

30import OpenAI from "openai";30import OpenAI from "openai";

31const openai = new OpenAI();31const openai = new OpenAI();

32 32 


44 44 

45if (imageData.length > 0) {45if (imageData.length > 0) {

46 const imageBase64 = imageData[0];46 const imageBase64 = imageData[0];

47 if (!imageBase64) throw new Error("Image generation returned no image.");

47 const fs = await import("fs");48 const fs = await import("fs");

48 fs.writeFileSync("otter.png", Buffer.from(imageBase64, "base64"));49 fs.writeFileSync("otter.png", Buffer.from(imageBase64, "base64"));

49}50}


254 255 

255 Multi-turn image generation256 Multi-turn image generation

256 257 

257```javascript258```typescript

258import OpenAI from "openai";259import OpenAI from "openai";

259const openai = new OpenAI();260const openai = new OpenAI();

260 261 


271 272 

272if (imageData.length > 0) {273if (imageData.length > 0) {

273 const imageBase64 = imageData[0];274 const imageBase64 = imageData[0];

275 if (!imageBase64) throw new Error("Image generation returned no image.");

274 const fs = await import("fs");276 const fs = await import("fs");

275 fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));277 fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));

276}278}


290 292 

291if (imageData_fwup.length > 0) {293if (imageData_fwup.length > 0) {

292 const imageBase64 = imageData_fwup[0];294 const imageBase64 = imageData_fwup[0];

295 if (!imageBase64) throw new Error("Image generation returned no image.");

293 const fs = await import("fs");296 const fs = await import("fs");

294 fs.writeFileSync(297 fs.writeFileSync(

295 "cat_and_otter_realistic.png",298 "cat_and_otter_realistic.png",


556 559 

557 Multi-turn image generation560 Multi-turn image generation

558 561 

559```javascript562```typescript

560import OpenAI from "openai";563import OpenAI from "openai";

561const openai = new OpenAI();564const openai = new OpenAI();

562 565 


575 578 

576if (imageData.length > 0) {579if (imageData.length > 0) {

577 const imageBase64 = imageData[0];580 const imageBase64 = imageData[0];

581 if (!imageBase64) throw new Error("Image generation returned no image.");

578 const fs = await import("fs");582 const fs = await import("fs");

579 fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));583 fs.writeFileSync("cat_and_otter.png", Buffer.from(imageBase64, "base64"));

580}584}


589 content: [{ type: "input_text", text: "Now make it look realistic" }],593 content: [{ type: "input_text", text: "Now make it look realistic" }],

590 },594 },

591 {595 {

592 type: "image_generation_call",596 type: "item_reference",

593 id: imageGenerationCalls[0].id,597 id: imageGenerationCalls[0].id,

594 },598 },

595 ],599 ],


602 606 

603if (imageData_fwup.length > 0) {607if (imageData_fwup.length > 0) {

604 const imageBase64 = imageData_fwup[0];608 const imageBase64 = imageData_fwup[0];

609 if (!imageBase64) throw new Error("Image generation returned no image.");

605 const fs = await import("fs");610 const fs = await import("fs");

606 fs.writeFileSync(611 fs.writeFileSync(

607 "cat_and_otter_realistic.png",612 "cat_and_otter_realistic.png",


915 920 

916Stream an image921Stream an image

917 922 

918```javascript923```typescript

919import OpenAI from "openai";924import OpenAI from "openai";

920import fs from "fs";925import fs from "fs";

921const openai = new OpenAI();926const openai = new OpenAI();

922 927 

923function saveBase64Image(filename, imageBase64) {928function saveBase64Image(filename: string, imageBase64: string | null) {

929 if (!imageBase64) throw new Error("Image generation returned no image.");

924 const imageBuffer = Buffer.from(imageBase64, "base64");930 const imageBuffer = Buffer.from(imageBase64, "base64");

925 fs.writeFileSync(filename, imageBuffer);931 fs.writeFileSync(filename, imageBuffer);

926}932}

Details

223 223 

224Run a programmatic tool-calling loop224Run a programmatic tool-calling loop

225 225 

226```javascript226```typescript

227import OpenAI from "openai";227import OpenAI from "openai";

228import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";228import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

229 229 

230const client = new OpenAI();230const client = new OpenAI();

231 231 

232const implementations = {232const implementations = {

233 get_inventory: async ({ sku }) => ({ sku, available_units: 42 }),233 get_inventory: async ({ sku }: { sku: string }) => ({

234 get_demand: async ({ sku }) => ({ sku, requested_units: 31 }),234 sku,

235 available_units: 42,

236 }),

237 get_demand: async ({ sku }: { sku: string }) => ({

238 sku,

239 requested_units: 31,

240 }),

235};241};

236 242 

237const tools = [243const tools: OpenAI.Responses.Tool[] = [

238 {244 {

239 type: "function",245 type: "function",

240 name: "get_inventory",246 name: "get_inventory",


284 { type: "programmatic_tool_calling" },290 { type: "programmatic_tool_calling" },

285];291];

286 292 

287const input = [293const input: OpenAI.Responses.ResponseInput = [

288 {294 {

289 role: "user",295 role: "user",

290 content: "Compare inventory with demand for sku_123.",296 content: "Compare inventory with demand for sku_123.",


320 326 

321 const outputs = await Promise.all(327 const outputs = await Promise.all(

322 calls.map(async (call) => {328 calls.map(async (call) => {

323 const run = implementations[call.name];329 const run = implementations[call.name as keyof typeof implementations];

324 if (!run) throw new Error(`Unknown tool: ${call.name}`);330 if (!run) throw new Error(`Unknown tool: ${call.name}`);

325 331 

326 const result = await run(JSON.parse(call.arguments));332 const result = await run(JSON.parse(call.arguments));

327 return {333 return {

328 type: "function_call_output",334 type: "function_call_output" as const,

329 call_id: call.call_id,335 call_id: call.call_id,

330 output: JSON.stringify(result),336 output: JSON.stringify(result),

331 // Preserve caller so the runtime can resume the correct program.337 // Preserve caller so the runtime can resume the correct program.

Details

45 }'45 }'

46```46```

47 47 

48```javascript48```typescript

49import OpenAI from "openai";49import OpenAI from "openai";

50 50 

51const client = new OpenAI();51const client = new OpenAI();


203 }'203 }'

204```204```

205 205 

206```javascript206```typescript

207import OpenAI from "openai";207import OpenAI from "openai";

208 208 

209const client = new OpenAI();209const client = new OpenAI();


316 }'316 }'

317```317```

318 318 

319```javascript319```typescript

320import OpenAI from "openai";320import OpenAI from "openai";

321 321 

322const client = new OpenAI();322const client = new OpenAI();


449 }'449 }'

450```450```

451 451 

452```javascript452```typescript

453import OpenAI from "openai";453import OpenAI from "openai";

454 454 

455const client = new OpenAI();455const client = new OpenAI();


611 }'611 }'

612```612```

613 613 

614```javascript614```typescript

615import OpenAI from "openai";615import OpenAI from "openai";

616 616 

617const client = new OpenAI();617const client = new OpenAI();


859 }'859 }'

860```860```

861 861 

862```javascript862```typescript

863import fs from "fs";863import fs from "fs";

864import OpenAI from "openai";864import OpenAI from "openai";

865 865 


1193 -H "Authorization: Bearer $OPENAI_API_KEY"1193 -H "Authorization: Bearer $OPENAI_API_KEY"

1194```1194```

1195 1195 

1196```javascript1196```typescript

1197import OpenAI from "openai";1197import OpenAI from "openai";

1198 1198 

1199const client = new OpenAI();1199const client = new OpenAI();


1309 }'1309 }'

1310```1310```

1311 1311 

1312```javascript1312```typescript

1313import OpenAI from "openai";1313import OpenAI from "openai";

1314 1314 

1315const client = new OpenAI();1315const client = new OpenAI();


1529 }'1529 }'

1530```1530```

1531 1531 

1532```javascript1532```typescript

1533import OpenAI from "openai";1533import OpenAI from "openai";

1534 1534 

1535const client = new OpenAI();1535const client = new OpenAI();


1696 }'1696 }'

1697```1697```

1698 1698 

1699```javascript1699```typescript

1700import OpenAI from "openai";1700import OpenAI from "openai";

1701 1701 

1702const client = new OpenAI();1702const client = new OpenAI();


1810 1810 

1811Local shell executor example1811Local shell executor example

1812 1812 

1813```javascript1813```typescript

1814import { spawn } from "node:child_process";1814import { spawn } from "node:child_process";

1815import type { Readable } from "node:stream";

1815 1816 

1816class ShellExecutor {1817class ShellExecutor {

1818 defaultTimeoutMs: number;

1817 constructor(defaultTimeoutMs = 60_000) {1819 constructor(defaultTimeoutMs = 60_000) {

1818 this.defaultTimeoutMs = defaultTimeoutMs;1820 this.defaultTimeoutMs = defaultTimeoutMs;

1819 }1821 }

1820 1822 

1821 async run(cmd, timeoutMs) {1823 async run(cmd: string, timeoutMs: number | undefined) {

1822 return new Promise((resolve, reject) => {1824 return new Promise<{

1825 stdout: string;

1826 stderr: string;

1827 exitCode: number | null;

1828 timedOut: boolean;

1829 }>((resolve, reject) => {

1823 const child = spawn("sh", ["-c", cmd], {1830 const child = spawn("sh", ["-c", cmd], {

1824 detached: true,1831 detached: true,

1825 stdio: ["ignore", "pipe", "pipe"],1832 stdio: ["ignore", "pipe", "pipe"],


1829 let timedOut = false;1836 let timedOut = false;

1830 let outputLimited = false;1837 let outputLimited = false;

1831 const stop = () => {1838 const stop = () => {

1839 if (child.pid === undefined) return;

1832 try {1840 try {

1833 process.kill(-child.pid, "SIGKILL");1841 process.kill(-child.pid, "SIGKILL");

1834 } catch (error) {1842 } catch (error) {

1835 if (error.code !== "ESRCH") reject(error);1843 if (

1844 !(

1845 error instanceof Error &&

1846 "code" in error &&

1847 error.code === "ESRCH"

1848 )

1849 )

1850 reject(error);

1836 }1851 }

1837 };1852 };

1838 const timer = setTimeout(() => {1853 const timer = setTimeout(() => {

1839 timedOut = true;1854 timedOut = true;

1840 stop();1855 stop();

1841 }, timeoutMs ?? this.defaultTimeoutMs);1856 }, timeoutMs ?? this.defaultTimeoutMs);

1842 const collect = (stream, append) => {1857 const collect = (stream: Readable, append: (chunk: string) => void) => {

1843 let bytes = 0;1858 let bytes = 0;

1844 stream.setEncoding("utf8");1859 stream.setEncoding("utf8");

1845 stream.on("data", (chunk) => {1860 stream.on("data", (chunk: string) => {

1846 bytes += Buffer.byteLength(chunk);1861 bytes += Buffer.byteLength(chunk);

1847 if (bytes > 1024 * 1024) {1862 if (bytes > 1024 * 1024) {

1848 outputLimited = true;1863 outputLimited = true;


1853 }1868 }

1854 });1869 });

1855 };1870 };

1856 collect(child.stdout, (chunk) => {1871 collect(child.stdout, (chunk: string) => {

1857 stdout += chunk;1872 stdout += chunk;

1858 });1873 });

1859 collect(child.stderr, (chunk) => {1874 collect(child.stderr, (chunk: string) => {

1860 stderr += chunk;1875 stderr += chunk;

1861 });1876 });

1862 child.on("error", (error) => {1877 child.on("error", (error) => {


2063 2078 

2064Use local shell with Agents SDK2079Use local shell with Agents SDK

2065 2080 

2066```javascript2081```typescript

2067import { Agent, run, withTrace, shellTool } from "@openai/agents";2082import {

2083 Agent,

2084 run,

2085 withTrace,

2086 shellTool,

2087 type ShellAction,

2088 type ShellResult,

2089} from "@openai/agents";

2068 2090 

2069class LocalShell {2091class LocalShell {

2070 async run(action) {2092 async run(action: ShellAction): Promise<ShellResult> {

2071 return {2093 return {

2072 output: [2094 output: [

2073 {2095 {

Details

108 }'108 }'

109```109```

110 110 

111```javascript111```typescript

112import OpenAI from "openai";112import OpenAI from "openai";

113 113 

114const client = new OpenAI();114const client = new OpenAI();


279 279 

280Use the [Shell guide](https://developers.openai.com/api/docs/guides/tools-shell) for local shell execution details.280Use the [Shell guide](https://developers.openai.com/api/docs/guides/tools-shell) for local shell execution details.

281 281 

282The JavaScript example requires Node.js and a running Docker daemon. Save the282The TypeScript example requires Node.js 22.6 or later and a running Docker daemon. Save the

283[Docker adapter](https://developers.openai.com/api/docs/samples/local-skill-sandbox.mjs) as `support/local-skill-sandbox.mjs` and283[Docker adapter](https://developers.openai.com/api/docs/samples/local-skill-sandbox.mjs) as `support/local-skill-sandbox.mjs` and

284the example as `tools/skills/local-shell.mjs` so its relative import resolves.284the example as `tools/skills/local-shell.mts` so its relative import resolves.

285Set `OPENAI_API_KEY`, then install the SDK, pull the adapter's pinned image, and285Set `OPENAI_API_KEY`, then install the SDK, pull the adapter's pinned image, and

286run the example from the directory containing `support` and `tools`:286run the example from the directory containing `support` and `tools`:

287 287 

288```bash288```bash

289npm install openai289npm install openai

290docker pull "$(node --input-type=module -e 'import { sandboxImage } from "./support/local-skill-sandbox.mjs"; console.log(sandboxImage)')"290docker pull "$(node --input-type=module -e 'import { sandboxImage } from "./support/local-skill-sandbox.mjs"; console.log(sandboxImage)')"

291node tools/skills/local-shell.mjs291node --experimental-strip-types tools/skills/local-shell.mts

292```292```

293 293 

294The adapter's helpers have these responsibilities:294The adapter's helpers have these responsibilities:


329 }'329 }'

330```330```

331 331 

332```javascript332```typescript

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

334import OpenAI from "openai";334import OpenAI from "openai";

335import {335import {


342// sandbox with the skill and CSV files; generated commands run only inside it.342// sandbox with the skill and CSV files; generated commands run only inside it.

343const name = "node-skill-" + randomUUID();343const name = "node-skill-" + randomUUID();

344 344 

345await withLocalSkillSandbox(name, async (signal) => {345await withLocalSkillSandbox(name, async (signal: AbortSignal) => {

346 const client = new OpenAI();346 const client = new OpenAI();

347 /** @type {OpenAI.Responses.ResponseCreateParamsNonStreaming} */347 /** @type {OpenAI.Responses.ResponseCreateParamsNonStreaming} */

348 const params = {348 const params: OpenAI.Responses.ResponseCreateParamsNonStreaming = {

349 model: "gpt-6-astra",349 model: "gpt-6-astra",

350 tools: [350 tools: [

351 {351 {

Details

19 19 

20Use Ultrafast across turns on one WebSocket20Use Ultrafast across turns on one WebSocket

21 21 

22```javascript22```typescript

23// Install: npm install openai ws23// Install: npm install openai ws

24// Set OPENAI_API_KEY in your environment.24// Set OPENAI_API_KEY in your environment.

25 25 


268 268 

269Create an Ultrafast response over HTTP269Create an Ultrafast response over HTTP

270 270 

271```javascript271```typescript

272import OpenAI from "openai";272import OpenAI from "openai";

273 273 

274const client = new OpenAI();274const client = new OpenAI();

Details

99 99 

100Use `session.instructions.append` for guardrail steering. It can interrupt speech in progress and apply a new instruction. For example, after your application blocks a request, send:100Use `session.instructions.append` for guardrail steering. It can interrupt speech in progress and apply a new instruction. For example, after your application blocks a request, send:

101 101 

102```javascript102```typescript

103export function sendUpdate(connection) {103import type { ClientEvent } from "openai/resources/live/live";

104 

105export function sendUpdate(connection: { send: (event: ClientEvent) => void }) {

104 connection.send({106 connection.send({

105 type: "session.instructions.append",107 type: "session.instructions.append",

106 event_id: "guardrail_block_17",108 event_id: "guardrail_block_17",


242 244 

2431. When [establishing a peer connection](https://developers.openai.com/api/docs/guides/voice-webrtc?api=realtime) you fetch and receive an SDP response from the Realtime API to configure the connection. If you used the sample code from the WebRTC guide, that looks something like this:2451. When [establishing a peer connection](https://developers.openai.com/api/docs/guides/voice-webrtc?api=realtime) you fetch and receive an SDP response from the Realtime API to configure the connection. If you used the sample code from the WebRTC guide, that looks something like this:

244 246 

245```javascript247```typescript

246const baseUrl = "https://api.openai.com/v1/realtime/calls";248const baseUrl = "https://api.openai.com/v1/realtime/calls";

247const sdpResponse = await fetch(baseUrl, {249const sdpResponse = await fetch(baseUrl, {

248 method: "POST",250 method: "POST",


257 259 

2582. The fetch response will contain a `Location` header that has a unique call ID that can be used on the server to establish a WebSocket connection to that same Realtime session.2602. The fetch response will contain a `Location` header that has a unique call ID that can be used on the server to establish a WebSocket connection to that same Realtime session.

259 261 

260```javascript262```typescript

261// Location: /v1/realtime/calls/rtc_123456263// Location: /v1/realtime/calls/rtc_123456

262const location = sdpResponse.headers.get("Location");264const location = sdpResponse.headers.get("Location");

263const callId = location?.split("/").pop();265const callId = location?.split("/").pop();


2683. On a server, you can then [listen for events and configure the session](https://developers.openai.com/api/docs/guides/realtime-conversations) just as you would from a typical Realtime API WebSocket connection, using that call ID with the URL2703. On a server, you can then [listen for events and configure the session](https://developers.openai.com/api/docs/guides/realtime-conversations) just as you would from a typical Realtime API WebSocket connection, using that call ID with the URL

269 `wss://api.openai.com/v1/realtime?call_id=rtc_xxxxx`, as shown below:271 `wss://api.openai.com/v1/realtime?call_id=rtc_xxxxx`, as shown below:

270 272 

271```javascript273```typescript

272import WebSocket from "ws";274import WebSocket from "ws";

273const callId = "rtc_u1_9c6574da8b8a41a18da9308f4ad974ce";275const callId = "rtc_u1_9c6574da8b8a41a18da9308f4ad974ce";

274 276 

Details

359track progress. See [Webhooks and server-side controls](https://developers.openai.com/api/docs/guides/voice-server-controls?api=realtime)359track progress. See [Webhooks and server-side controls](https://developers.openai.com/api/docs/guides/voice-server-controls?api=realtime)

360for more information.360for more information.

361 361 

362```javascript362```typescript

363import WebSocket from "ws";363import WebSocket from "ws";

364 364 

365const callId = "rtc_u1_9c6574da8b8a41a18da9308f4ad974ce";365const callId = "rtc_u1_9c6574da8b8a41a18da9308f4ad974ce";

Details

36 36 

37### Create the application server37### Create the application server

38 38 

39Save the server example in a new directory and set `OPENAI_API_KEY` in its environment. For Node.js, use `server.mjs` and install `openai` and `express` with `npm install openai express`. For Python, install `openai`. This example binds to `127.0.0.1`, accepts session requests from `http://localhost:3000`, and serves `index.html` from the directory where you run it.39Save the server example in a new directory and set `OPENAI_API_KEY` in its environment. For TypeScript, use Node.js 22.6 or later, save the example as `server.ts`, and run `npm install openai express` followed by `npm pkg set type=module`. For Python, install `openai`. This example binds to `127.0.0.1`, accepts session requests from `http://localhost:3000`, and serves `index.html` from the directory where you run it.

40 40 

41For Go, save the example as `main.go`, initialize a module with `go mod init live-demo`, and install `github.com/openai/openai-go/v3@v3.85.1` with `go get`. Run `go run .` with Go 1.26 or later. For Java, use Java 17 or later, add the Maven dependency `com.openai:openai-java:4.95.0`, and run the `LiveConnectionWebrtcExample` class. For Ruby 3.3 or later, install `openai` 0.110.0 and `webrick` with `gem install openai -v 0.110.0` and `gem install webrick`, save the example as `server.rb`, and run `ruby server.rb`.41For Go, save the example as `main.go`, initialize a module with `go mod init live-demo`, and install `github.com/openai/openai-go/v3@v3.85.1` with `go get`. Run `go run .` with Go 1.26 or later. For Java, use Java 17 or later, add the Maven dependency `com.openai:openai-java:4.95.0`, and run the `LiveConnectionWebrtcExample` class. For Ruby 3.3 or later, install `openai` 0.110.0 and `webrick` with `gem install openai -v 0.110.0` and `gem install webrick`, save the example as `server.rb`, and run `ruby server.rb`.

42 42 

43Choose a server language below; each variant serves `index.html` and the same `/api/session` endpoint on port 3000. Use an SDK version with Live support. Run only one variant at a time.43Choose a server language below; each variant serves `index.html` and the same `/api/session` endpoint on port 3000. Use an SDK version with Live support. Run only one variant at a time.

44 44 

45```javascript45```typescript

46import express from "express";46import express from "express";

47import OpenAI from "openai";47import OpenAI from "openai";

48import { readFile } from "node:fs/promises";48import { readFile } from "node:fs/promises";


480 </head>480 </head>

481 <body>481 <body>

482 <script type="module">482 <script type="module">

483 // Paste the browser code below here.483 // Paste the compiled contents of browser.js here.

484 </script>484 </script>

485 </body>485 </body>

486</html>486</html>

487```487```

488 488 

489 489 

490Paste the following code inside the module script. It adds start and end controls, connects the microphone and output audio, and handles session events. `/api/session` is a route on your application server.490Save the following TypeScript code as `browser.ts`. It adds start and end controls, connects the microphone and output audio, and handles session events. `/api/session` is a route on your application server.

491 491 

492```javascript492```typescript

493const start = document.createElement("button");493const start = document.createElement("button");

494start.textContent = "Start conversation";494start.textContent = "Start conversation";

495const stop = document.createElement("button");495const stop = document.createElement("button");


501audio.controls = true;501audio.controls = true;

502document.body.append(start, stop, status, audio);502document.body.append(start, stop, status, audio);

503 503 

504let peer;504let peer: RTCPeerConnection;

505 505 

506let events;506let events: RTCDataChannel | undefined;

507 507 

508let microphone;508let microphone: MediaStream;

509 509 

510let closeTimeout;510let closeTimeout: ReturnType<typeof setTimeout> | undefined;

511let ready = false;511let ready = false;

512let finalized = false;512let finalized = false;

513 513 


626```626```

627 627 

628 628 

629Run your chosen server (`node server.mjs` or `python server.py`), open `http://localhost:3000`, and select **Start conversation**. After the status changes to **Connected**, ask a question that needs current information to exercise hosted search. Use the audio controls if your browser blocks autoplay.629Compile `browser.ts`, then replace the placeholder in the module script with the contents of the generated `browser.js` file:

630 

631```bash

632npm install --save-dev esbuild

633npx esbuild browser.ts --format=esm --outfile=browser.js

634```

635 

636 

637Run your chosen server (`node --experimental-strip-types server.ts` or `python server.py`), open `http://localhost:3000`, and select **Start conversation**. After the status changes to **Connected**, ask a question that needs current information to exercise hosted search. Use the audio controls if your browser blocks autoplay.

630 638 

631### Read the session response639### Read the session response

632 640 


684 692 

685Create a Realtime API session from your application server:693Create a Realtime API session from your application server:

686 694 

687```javascript695```typescript

688import express from "express";696import express from "express";

689 697 

690const app = express();698const app = express();


783 791 

784In the browser, you can use standard WebRTC APIs to connect to the Realtime API via your application server. The client sends its SDP data to your server in a `POST` request.792In the browser, you can use standard WebRTC APIs to connect to the Realtime API via your application server. The client sends its SDP data to your server in a `POST` request.

785 793 

786```javascript794```typescript

787// Create a peer connection795// Create a peer connection

788const pc = new RTCPeerConnection();796const pc = new RTCPeerConnection();

789 797 


837 845 

838Create an ephemeral API key from your application server using the REST API:846Create an ephemeral API key from your application server using the REST API:

839 847 

840```javascript848```typescript

841import express from "express";849import express from "express";

842 850 

843const app = express();851const app = express();


927 935 

928In the browser, you can use standard WebRTC APIs to connect to the Realtime API with an ephemeral token. The client first fetches a token from your server endpoint, and then sends its SDP data (with the ephemeral token) to the Realtime API in a `POST` request.936In the browser, you can use standard WebRTC APIs to connect to the Realtime API with an ephemeral token. The client first fetches a token from your server endpoint, and then sends its SDP data (with the ephemeral token) to the Realtime API in a `POST` request.

929 937 

930```javascript938```typescript

931// Get a session token for OpenAI Realtime API939// Get a session token for OpenAI Realtime API

932const tokenResponse = await fetch("/token");940const tokenResponse = await fetch("/token");

933const data = await tokenResponse.json();941const data = await tokenResponse.json();


985 993 

986To send and receive other client and server events, you can use the WebRTC peer connection's [data channel](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Using_data_channels).994To send and receive other client and server events, you can use the WebRTC peer connection's [data channel](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Using_data_channels).

987 995 

988```javascript996```typescript

989// Reuse dc from the preceding browser connection example.997// Reuse dc from the preceding browser connection example.

990 998 

991// Listen for server events999// Listen for server events

Details

24 24 

25### Stream audio with an SDK25### Stream audio with an SDK

26 26 

27For Node.js, install `openai` and `ws` with `npm install openai ws` and save the JavaScript example as `client.mjs`. For Python on macOS or Linux, install `openai[realtime]` and save the Python example as `client.py`. Set `OPENAI_API_KEY` in the server environment. These examples require an SDK version with Live support. The example reads raw, mono PCM16 audio at 24 kHz from standard input and writes returned audio in the same format to standard output. Connect these streams to your application's audio capture and playback. Logs and transcript events go to standard error so they do not corrupt the audio stream.27For Node.js 22.6 or later, install `openai` and `ws` with `npm install openai ws` and save the TypeScript example as `client.mts`. For Python on macOS or Linux, install `openai[realtime]` and save the Python example as `client.py`. Set `OPENAI_API_KEY` in the server environment. These examples require an SDK version with Live support. The example reads raw, mono PCM16 audio at 24 kHz from standard input and writes returned audio in the same format to standard output. Connect these streams to your application's audio capture and playback. Logs and transcript events go to standard error so they do not corrupt the audio stream.

28 28 

29For Go, use Go 1.26 or later, save the example as `main.go`, initialize a module with `go mod init live-demo`, and install `github.com/openai/openai-go/v3@v3.85.1` with `go get`. For Java, use Java 17 or later, add the Maven dependency `com.openai:openai-java:4.95.0`, and use the `LiveConnectionWebsocketExample` class. For Ruby 3.3 or later, install the SDK with `gem install openai -v 0.110.0`, install its WebSocket dependency with `gem install async-websocket`, and save the example as `client.rb`.29For Go, use Go 1.26 or later, save the example as `main.go`, initialize a module with `go mod init live-demo`, and install `github.com/openai/openai-go/v3@v3.85.1` with `go get`. For Java, use Java 17 or later, add the Maven dependency `com.openai:openai-java:4.95.0`, and use the `LiveConnectionWebsocketExample` class. For Ruby 3.3 or later, install the SDK with `gem install openai -v 0.110.0`, install its WebSocket dependency with `gem install async-websocket`, and save the example as `client.rb`.

30 30 

31```javascript31```typescript

32import OpenAI from "openai";32import OpenAI from "openai";

33import { LiveWS } from "openai/resources/live/ws";33import { LiveWS } from "openai/resources/live/ws";

34 34 


41let finalized = false;41let finalized = false;

42let pendingByte = Buffer.alloc(0);42let pendingByte = Buffer.alloc(0);

43 43 

44let closeTimeout;44let closeTimeout: ReturnType<typeof setTimeout> | undefined;

45 45 

46ws.socket.on("open", () => {46ws.socket.on("open", () => {

47 ws.send({47 ws.send({


642```642```

643 643 

644 644 

645Run `node client.mjs`, `python client.py`, `go run .`, `ruby client.rb`, or your Java application with your audio source and player attached. After `Session ready` appears, supply a continuous microphone stream paced at its recorded sample rate. Piping an entire file at once does not simulate a live microphone. EOF on the audio source does not end the conversation. Send `SIGINT` to the process to request a graceful close.645Run `node --experimental-strip-types client.mts`, `python client.py`, `go run .`, `ruby client.rb`, or your Java application with your audio source and player attached. After `Session ready` appears, supply a continuous microphone stream paced at its recorded sample rate. Piping an entire file at once does not simulate a live microphone. EOF on the audio source does not end the conversation. Send `SIGINT` to the process to request a graceful close.

646 646 

647The example connects the audio streams; your application handles capture, buffering, playback, and resampling when needed. Test these parts with your devices and network before evaluating model behavior.647The example connects the audio streams; your application handles capture, buffering, playback, and resampling when needed. Test these parts with your devices and network before evaluating model behavior.

648 648 


724 724 

725 Connect using the ws module (Node.js)725 Connect using the ws module (Node.js)

726 726 

727```javascript727```typescript

728import WebSocket from "ws";728import WebSocket from "ws";

729 729 

730const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1";730const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1";


963 963 

964 Connect with standard WebSocket (browsers)964 Connect with standard WebSocket (browsers)

965 965 

966```javascript966```typescript

967/*967/*

968Note that in client-side environments like web browsers, we recommend968Note that in client-side environments like web browsers, we recommend

969using WebRTC instead. It is possible, however, to use the standard969using WebRTC instead. It is possible, however, to use the standard


997 997 

998Over a WebSocket, you will both send and receive JSON-serialized events as strings of text, as in this Node.js example below (the same principles apply for other WebSocket libraries):998Over a WebSocket, you will both send and receive JSON-serialized events as strings of text, as in this Node.js example below (the same principles apply for other WebSocket libraries):

999 999 

1000```javascript1000```typescript

1001import WebSocket from "ws";1001import WebSocket from "ws";

1002 1002 

1003const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1";1003const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1";


1032 1032 

1033The WebSocket interface is perhaps the lowest-level interface available to interact with a Realtime model, where you will be responsible for both sending and processing Base64-encoded audio chunks over the socket connection.1033The WebSocket interface is perhaps the lowest-level interface available to interact with a Realtime model, where you will be responsible for both sending and processing Base64-encoded audio chunks over the socket connection.

1034 1034 

1035To learn how to send and receive audio over Websockets, refer to the [Realtime conversations guide](https://developers.openai.com/api/docs/guides/realtime-conversations#handling-audio-with-websockets).1035To learn how to send and receive audio over WebSockets, refer to the [Realtime conversations guide](https://developers.openai.com/api/docs/guides/realtime-conversations#handling-audio-with-websockets).

1036 1036 

1037 1037

1038 1038 

Details

24 24 

25Webhooks server25Webhooks server

26 26 

27```javascript27```typescript

28import OpenAI from "openai";28import OpenAI from "openai";

29import express from "express";29import express from "express";

30 30 


165}'165}'

166```166```

167 167 

168```javascript168```typescript

169import OpenAI from "openai";169import OpenAI from "openai";

170const client = new OpenAI();170const client = new OpenAI();

171 171 


341 341 

342Signature verification with the OpenAI SDK342Signature verification with the OpenAI SDK

343 343 

344```javascript344```typescript

345const client = new OpenAI();345const client = new OpenAI();

346const webhook_secret = process.env.OPENAI_WEBHOOK_SECRET;346const webhook_secret = process.env.OPENAI_WEBHOOK_SECRET;

347if (!webhook_secret) throw new Error("Set OPENAI_WEBHOOK_SECRET.");347if (!webhook_secret) throw new Error("Set OPENAI_WEBHOOK_SECRET.");

Details

22 22 

23In WebSocket mode, start each turn by sending a `response.create` event from the client. The payload mirrors the normal [Responses create body](https://developers.openai.com/api/reference/resources/responses/methods/create), except that transport-specific fields like `stream` and `background` are not used.23In WebSocket mode, start each turn by sending a `response.create` event from the client. The payload mirrors the normal [Responses create body](https://developers.openai.com/api/reference/resources/responses/methods/create), except that transport-specific fields like `stream` and `background` are not used.

24 24 

25```javascript25```typescript

26import OpenAI from "openai";26import OpenAI from "openai";

27import { ResponsesWS } from "openai/resources/responses/ws";27import { ResponsesWS } from "openai/resources/responses/ws";

28 28 


204- `previous_response_id` set to the prior response ID.204- `previous_response_id` set to the prior response ID.

205- `input` containing only new items (for example, tool outputs and the next user message).205- `input` containing only new items (for example, tool outputs and the next user message).

206 206 

207```javascript207```typescript

208import OpenAI from "openai";208import OpenAI from "openai";

209import { ResponsesWS } from "openai/resources/responses/ws";209import { ResponsesWS } from "openai/resources/responses/ws";

210 210 

211const client = new OpenAI();211const client = new OpenAI();

212const model = "gpt-6-astra";212const model = "gpt-6-astra";

213 213 

214const tools = [214const tools: OpenAI.Responses.Tool[] = [

215 {215 {

216 type: "function",216 type: "function",

217 name: "get_test_results",217 name: "get_test_results",


221 },221 },

222];222];

223 223 

224async function waitForResponse(ws) {224async function waitForResponse(ws: ResponsesWS) {

225 for await (const event of ws) {225 for await (const event of ws) {

226 if (event.type === "error") throw event.error;226 if (event.type === "error") throw event.error;

227 if (event.type !== "message") continue;227 if (event.type !== "message") continue;


642 642 

643Start a new chain by omitting `previous_response_id` or setting it to `null`. Pass the compacted output as-is; do not prune the returned window.643Start a new chain by omitting `previous_response_id` or setting it to `null`. Pass the compacted output as-is; do not prune the returned window.

644 644 

645```javascript645```typescript

646import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";646import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

647 647 

648// Compact your current window with an HTTP request.648// Compact your current window with an HTTP request.


844 844 

845Run parallel conversations, then fork one845Run parallel conversations, then fork one

846 846 

847```javascript847```typescript

848import OpenAI from "openai";848import OpenAI from "openai";

849import type { ResponsesStreamMessage } from "openai/resources/responses/internal-base.mjs";

849import { ResponsesWS } from "openai/resources/responses/ws";850import { ResponsesWS } from "openai/resources/responses/ws";

850 851 

851const client = new OpenAI();852const client = new OpenAI();


853const latestResponseIdByLane = new Map();854const latestResponseIdByLane = new Map();

854 855 

855function sendCreate(856function sendCreate(

856 ws,857 ws: ResponsesWS,

857 streamId,858 streamId: string,

858 text,859 text: string,

859 previousResponseId = latestResponseIdByLane.get(streamId)860 previousResponseId = latestResponseIdByLane.get(streamId)

860) {861) {

861 ws.send({862 ws.send({


874 });875 });

875}876}

876 877 

877async function readMessage(events) {878async function readMessage(

879 events: AsyncIterableIterator<ResponsesStreamMessage>

880) {

878 while (true) {881 while (true) {

879 const { value: event, done } = await events.next();882 const { value: event, done } = await events.next();

880 if (done)883 if (done)


894 }897 }

895}898}

896 899 

897async function drainUntilComplete(events, expectedStreamIds) {900async function drainUntilComplete(

901 events: AsyncIterableIterator<ResponsesStreamMessage>,

902 expectedStreamIds: Iterable<unknown> | null | undefined

903) {

898 const remaining = new Set(expectedStreamIds);904 const remaining = new Set(expectedStreamIds);

899 while (remaining.size > 0) {905 while (remaining.size > 0) {

900 const message = await readMessage(events);906 const message = await readMessage(events);


907 }913 }

908}914}

909 915 

910async function waitForInProgress(events, streamId) {916async function waitForInProgress(

917 events: AsyncIterableIterator<ResponsesStreamMessage>,

918 streamId: string

919) {

911 while (true) {920 while (true) {

912 const message = await readMessage(events);921 const message = await readMessage(events);

913 if (922 if (

Details

72 72 

73Before configuring workload identity federation, export the AWS-issued token as `TOKEN`, then run this script locally to inspect its claims:73Before configuring workload identity federation, export the AWS-issued token as `TOKEN`, then run this script locally to inspect its claims:

74 74 

75```javascript75```typescript

76const parts = process.env.TOKEN?.split(".") ?? [];76const parts = process.env.TOKEN?.split(".") ?? [];

77if (parts.length !== 3) {77if (parts.length !== 3) {

78 throw new Error("Expected a compact JWT with three segments");78 throw new Error("Expected a compact JWT with three segments");


440 440 

441Authenticate from an AWS-issued OIDC token441Authenticate from an AWS-issued OIDC token

442 442 

443```javascript443```typescript

444import { GetWebIdentityTokenCommand, STSClient } from "@aws-sdk/client-sts";444import { GetWebIdentityTokenCommand, STSClient } from "@aws-sdk/client-sts";

445import OpenAI from "openai";445import OpenAI from "openai";

446 446 


460 460 

461function awsOutboundWebIdentityTokenProvider() {461function awsOutboundWebIdentityTokenProvider() {

462 return {462 return {

463 tokenType: "jwt",463 tokenType: "jwt" as const,

464 getToken: async () => {464 getToken: async () => {

465 const response = await sts.send(465 const response = await sts.send(

466 new GetWebIdentityTokenCommand({466 new GetWebIdentityTokenCommand({


858 858 

859Then run this script:859Then run this script:

860 860 

861```javascript861```typescript

862const parts = process.env.TOKEN?.split(".") ?? [];862const parts = process.env.TOKEN?.split(".") ?? [];

863if (parts.length !== 3) {863if (parts.length !== 3) {

864 throw new Error("Expected a compact JWT with three segments");864 throw new Error("Expected a compact JWT with three segments");


1213 1213 

1214Authenticate from an EKS projected service account token1214Authenticate from an EKS projected service account token

1215 1215 

1216```javascript1216```typescript

1217import { readFile } from "node:fs/promises";1217import { readFile } from "node:fs/promises";

1218import OpenAI from "openai";1218import OpenAI from "openai";

1219 1219 


1227 );1227 );

1228}1228}

1229 1229 

1230function mountedEksServiceAccountTokenProvider(path) {1230function mountedEksServiceAccountTokenProvider(path: string) {

1231 return {1231 return {

1232 tokenType: "jwt",1232 tokenType: "jwt" as const,

1233 getToken: async () => {1233 getToken: async () => {

1234 const token = (await readFile(path, "utf8")).trim();1234 const token = (await readFile(path, "utf8")).trim();

1235 if (!token) {1235 if (!token) {

Details

48 48 

49Before configuring workload identity federation, export the GitHub OIDC token as `TOKEN`, then run this script in the workflow runner to inspect its claims:49Before configuring workload identity federation, export the GitHub OIDC token as `TOKEN`, then run this script in the workflow runner to inspect its claims:

50 50 

51```javascript51```typescript

52const parts = process.env.TOKEN?.split(".") ?? [];52const parts = process.env.TOKEN?.split(".") ?? [];

53if (parts.length !== 3) {53if (parts.length !== 3) {

54 throw new Error("Expected a compact JWT with three segments");54 throw new Error("Expected a compact JWT with three segments");


432 steps:432 steps:

433 - uses: actions/checkout@v4433 - uses: actions/checkout@v4

434 434 

435 - uses: actions/setup-node@v4

436 with:

437 node-version: 22

438 

435 - name: Run OpenAI SDK code439 - name: Run OpenAI SDK code

436 env:440 env:

437 OPENAI_WIF_AUDIENCE: ${{ vars.OPENAI_WIF_AUDIENCE }}441 OPENAI_WIF_AUDIENCE: ${{ vars.OPENAI_WIF_AUDIENCE }}

438 OPENAI_IDENTITY_PROVIDER_ID: ${{ vars.OPENAI_IDENTITY_PROVIDER_ID }}442 OPENAI_IDENTITY_PROVIDER_ID: ${{ vars.OPENAI_IDENTITY_PROVIDER_ID }}

439 OPENAI_SERVICE_ACCOUNT_ID: ${{ vars.OPENAI_SERVICE_ACCOUNT_ID }}443 OPENAI_SERVICE_ACCOUNT_ID: ${{ vars.OPENAI_SERVICE_ACCOUNT_ID }}

440 run: node ./scripts/call-openai.js444 run: node --experimental-strip-types ./scripts/call-openai.mts

441```445```

442 446 

443Store `OPENAI_WIF_AUDIENCE`, `OPENAI_IDENTITY_PROVIDER_ID`, and `OPENAI_SERVICE_ACCOUNT_ID` as GitHub Actions variables. They identify the provider and service account but are not bearer credentials.447Store `OPENAI_WIF_AUDIENCE`, `OPENAI_IDENTITY_PROVIDER_ID`, and `OPENAI_SERVICE_ACCOUNT_ID` as GitHub Actions variables. They identify the provider and service account but are not bearer credentials.


446 450 

447Authenticate from a GitHub Actions OIDC token451Authenticate from a GitHub Actions OIDC token

448 452 

449```javascript453```typescript

450import OpenAI from "openai";454import OpenAI from "openai";

451 455 

452const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;456const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;


467 );471 );

468}472}

469 473 

470function githubActionsOIDCTokenProvider(requestURL, requestToken, audience) {474function githubActionsOIDCTokenProvider(

475 requestURL: string | URL,

476 requestToken: string,

477 audience: string

478) {

471 return {479 return {

472 tokenType: "jwt",480 tokenType: "jwt" as const,

473 getToken: async () => {481 getToken: async () => {

474 const url = new URL(requestURL);482 const url = new URL(requestURL);

475 url.searchParams.set("audience", audience);483 url.searchParams.set("audience", audience);

Details

48 48 

49Before configuring workload identity federation, export the Google identity token as `TOKEN`, then run this script locally to inspect its claims:49Before configuring workload identity federation, export the Google identity token as `TOKEN`, then run this script locally to inspect its claims:

50 50 

51```javascript51```typescript

52const parts = process.env.TOKEN?.split(".") ?? [];52const parts = process.env.TOKEN?.split(".") ?? [];

53if (parts.length !== 3) {53if (parts.length !== 3) {

54 throw new Error("Expected a compact JWT with three segments");54 throw new Error("Expected a compact JWT with three segments");


395 395 

396Authenticate from a Google metadata server identity token396Authenticate from a Google metadata server identity token

397 397 

398```javascript398```typescript

399import OpenAI from "openai";399import OpenAI from "openai";

400 400 

401const metadataEndpoint =401const metadataEndpoint =


411 );411 );

412}412}

413 413 

414function googleMetadataIdentityTokenProvider(audience) {414function googleMetadataIdentityTokenProvider(audience: string) {

415 return {415 return {

416 tokenType: "jwt",416 tokenType: "jwt" as const,

417 getToken: async () => {417 getToken: async () => {

418 const url = new URL(metadataEndpoint);418 const url = new URL(metadataEndpoint);

419 url.searchParams.set("audience", audience);419 url.searchParams.set("audience", audience);


885 885 

886Then run this script:886Then run this script:

887 887 

888```javascript888```typescript

889const parts = process.env.TOKEN?.split(".") ?? [];889const parts = process.env.TOKEN?.split(".") ?? [];

890if (parts.length !== 3) {890if (parts.length !== 3) {

891 throw new Error("Expected a compact JWT with three segments");891 throw new Error("Expected a compact JWT with three segments");


1238 1238 

1239Authenticate from a GKE projected service account token1239Authenticate from a GKE projected service account token

1240 1240 

1241```javascript1241```typescript

1242import { readFile } from "node:fs/promises";1242import { readFile } from "node:fs/promises";

1243import OpenAI from "openai";1243import OpenAI from "openai";

1244 1244 


1252 );1252 );

1253}1253}

1254 1254 

1255function mountedGkeServiceAccountTokenProvider(path) {1255function mountedGkeServiceAccountTokenProvider(path: string) {

1256 return {1256 return {

1257 tokenType: "jwt",1257 tokenType: "jwt" as const,

1258 getToken: async () => {1258 getToken: async () => {

1259 const token = (await readFile(path, "utf8")).trim();1259 const token = (await readFile(path, "utf8")).trim();

1260 if (!token) {1260 if (!token) {

Details

62export TOKEN="$(cat /var/run/spiffe/openai.jwt)"62export TOKEN="$(cat /var/run/spiffe/openai.jwt)"

63```63```

64 64 

65```javascript65```typescript

66const parts = process.env.TOKEN?.split(".") ?? [];66const parts = process.env.TOKEN?.split(".") ?? [];

67if (parts.length !== 3) {67if (parts.length !== 3) {

68 throw new Error("Expected a compact JWT with three segments");68 throw new Error("Expected a compact JWT with three segments");

69}69}

70 70 

71const decode = (segment) => {71const decode = (segment: string) => {

72 if (!/^[A-Za-z0-9_-]+$/.test(segment) || segment.length % 4 === 1) {72 if (!/^[A-Za-z0-9_-]+$/.test(segment) || segment.length % 4 === 1) {

73 throw new Error("JWT segment is not valid Base64URL");73 throw new Error("JWT segment is not valid Base64URL");

74 }74 }


457 457 

458Authenticate with an Idira-issued SPIFFE JWT-SVID458Authenticate with an Idira-issued SPIFFE JWT-SVID

459 459 

460```javascript460```typescript

461import { readFile } from "node:fs/promises";461import { readFile } from "node:fs/promises";

462import OpenAI from "openai";462import OpenAI from "openai";

463 463 


471 );471 );

472}472}

473 473 

474function spiffeJwtSvidProvider(path) {474function spiffeJwtSvidProvider(path: string) {

475 return {475 return {

476 tokenType: "jwt",476 tokenType: "jwt" as const,

477 getToken: async () => {477 getToken: async () => {

478 const token = (await readFile(path, "utf8")).trim();478 const token = (await readFile(path, "utf8")).trim();

479 if (!token) {479 if (!token) {

Details

66 66 

67Then run this script:67Then run this script:

68 68 

69```javascript69```typescript

70const parts = process.env.TOKEN?.split(".") ?? [];70const parts = process.env.TOKEN?.split(".") ?? [];

71if (parts.length !== 3) {71if (parts.length !== 3) {

72 throw new Error("Expected a compact JWT with three segments");72 throw new Error("Expected a compact JWT with three segments");


423 423 

424Authenticate from a Kubernetes projected service account token424Authenticate from a Kubernetes projected service account token

425 425 

426```javascript426```typescript

427import { readFile } from "node:fs/promises";427import { readFile } from "node:fs/promises";

428import OpenAI from "openai";428import OpenAI from "openai";

429 429 


437 );437 );

438}438}

439 439 

440function mountedServiceAccountTokenProvider(path) {440function mountedServiceAccountTokenProvider(path: string) {

441 return {441 return {

442 tokenType: "jwt",442 tokenType: "jwt" as const,

443 getToken: async () => {443 getToken: async () => {

444 const token = (await readFile(path, "utf8")).trim();444 const token = (await readFile(path, "utf8")).trim();

445 if (!token) {445 if (!token) {

Details

44 44 

45Before configuring workload identity federation, export the Microsoft Entra token as `TOKEN`, then run this script locally to inspect its claims:45Before configuring workload identity federation, export the Microsoft Entra token as `TOKEN`, then run this script locally to inspect its claims:

46 46 

47```javascript47```typescript

48const parts = process.env.TOKEN?.split(".") ?? [];48const parts = process.env.TOKEN?.split(".") ?? [];

49if (parts.length !== 3) {49if (parts.length !== 3) {

50 throw new Error("Expected a compact JWT with three segments");50 throw new Error("Expected a compact JWT with three segments");


410 410 

411Authenticate from an Azure managed identity token411Authenticate from an Azure managed identity token

412 412 

413```javascript413```typescript

414import OpenAI from "openai";414import OpenAI from "openai";

415 415 

416const imdsEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token";416const imdsEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token";


425 );425 );

426}426}

427 427 

428function azureManagedIdentityTokenProvider(resource) {428function azureManagedIdentityTokenProvider(resource: string) {

429 return {429 return {

430 tokenType: "jwt",430 tokenType: "jwt" as const,

431 getToken: async () => {431 getToken: async () => {

432 const url = new URL(imdsEndpoint);432 const url = new URL(imdsEndpoint);

433 url.searchParams.set("api-version", "2018-02-01");433 url.searchParams.set("api-version", "2018-02-01");


920 920 

921Then run this script:921Then run this script:

922 922 

923```javascript923```typescript

924const parts = process.env.TOKEN?.split(".") ?? [];924const parts = process.env.TOKEN?.split(".") ?? [];

925if (parts.length !== 3) {925if (parts.length !== 3) {

926 throw new Error("Expected a compact JWT with three segments");926 throw new Error("Expected a compact JWT with three segments");


1281 1281 

1282Authenticate from an AKS projected service account token1282Authenticate from an AKS projected service account token

1283 1283 

1284```javascript1284```typescript

1285import { readFile } from "node:fs/promises";1285import { readFile } from "node:fs/promises";

1286import OpenAI from "openai";1286import OpenAI from "openai";

1287 1287 


1295 );1295 );

1296}1296}

1297 1297 

1298function mountedAksServiceAccountTokenProvider(path) {1298function mountedAksServiceAccountTokenProvider(path: string) {

1299 return {1299 return {

1300 tokenType: "jwt",1300 tokenType: "jwt" as const,

1301 getToken: async () => {1301 getToken: async () => {

1302 const token = (await readFile(path, "utf8")).trim();1302 const token = (await readFile(path, "utf8")).trim();

1303 if (!token) {1303 if (!token) {

Details

39 39 

40Set `TOKEN` to an access token generated by the actual OCI workload, then use the existing local JWT decoder to inspect its claims:40Set `TOKEN` to an access token generated by the actual OCI workload, then use the existing local JWT decoder to inspect its claims:

41 41 

42```javascript42```typescript

43const parts = process.env.TOKEN?.split(".") ?? [];43const parts = process.env.TOKEN?.split(".") ?? [];

44if (parts.length !== 3) {44if (parts.length !== 3) {

45 throw new Error("Expected a compact JWT with three segments");45 throw new Error("Expected a compact JWT with three segments");

Details

87 87 

88Before configuring workload identity federation, export the JWT-SVID as `TOKEN`, then run one of these examples locally to inspect its header and claims:88Before configuring workload identity federation, export the JWT-SVID as `TOKEN`, then run one of these examples locally to inspect its header and claims:

89 89 

90```javascript90```typescript

91const parts = process.env.TOKEN?.split(".") ?? [];91const parts = process.env.TOKEN?.split(".") ?? [];

92if (parts.length !== 3) {92if (parts.length !== 3) {

93 throw new Error("Expected a compact JWT with three segments");93 throw new Error("Expected a compact JWT with three segments");

94}94}

95 95 

96const decode = (segment) => {96const decode = (segment: string) => {

97 if (!/^[A-Za-z0-9_-]+$/.test(segment) || segment.length % 4 === 1) {97 if (!/^[A-Za-z0-9_-]+$/.test(segment) || segment.length % 4 === 1) {

98 throw new Error("JWT segment is not valid Base64URL");98 throw new Error("JWT segment is not valid Base64URL");

99 }99 }


485 485 

486Authenticate from a SPIFFE JWT-SVID486Authenticate from a SPIFFE JWT-SVID

487 487 

488```javascript488```typescript

489import { readFile } from "node:fs/promises";489import { readFile } from "node:fs/promises";

490import OpenAI from "openai";490import OpenAI from "openai";

491 491 


499 );499 );

500}500}

501 501 

502function spiffeJwtSvidProvider(path) {502function spiffeJwtSvidProvider(path: string) {

503 return {503 return {

504 tokenType: "jwt",504 tokenType: "jwt" as const,

505 getToken: async () => {505 getToken: async () => {

506 const token = (await readFile(path, "utf8")).trim();506 const token = (await readFile(path, "utf8")).trim();

507 if (!token) {507 if (!token) {

Details

112 112 

113Authenticate with an X.509 client certificate113Authenticate with an X.509 client certificate

114 114 

115```javascript115```typescript

116import { readFile } from "node:fs/promises";116import { readFile } from "node:fs/promises";

117 117 

118import OpenAI from "openai";118import OpenAI from "openai";


358```358```

359 359 

360 360 

361These examples require OpenAI SDK versions that support the X.509 configuration shown here: JavaScript 7.8.0 or later with the `undici` peer dependency installed, Python 3.6.0 or later, Go 3.54.0 or later, Java 4.55.0 or later, and Ruby 0.83.0 or later.361These examples require OpenAI SDK versions that support the X.509 configuration shown here: TypeScript 7.8.0 or later with the `undici` peer dependency installed, Python 3.6.0 or later, Go 3.54.0 or later, Java 4.55.0 or later, and Ruby 0.83.0 or later.

362 362 

363The Java example loads a PKCS12 keystore to construct its `X509ExtendedKeyManager` and uses the platform default trust store to construct its `X509TrustManager`. Set `OPENAI_X509_KEYSTORE_PATH`, `OPENAI_X509_KEYSTORE_PASSWORD`, and `OPENAI_X509_CERTIFICATE_ALIAS` for this example. You can instead supply PEM-backed or hardware-backed managers to the SDK.363The Java example loads a PKCS12 keystore to construct its `X509ExtendedKeyManager` and uses the platform default trust store to construct its `X509TrustManager`. Set `OPENAI_X509_KEYSTORE_PATH`, `OPENAI_X509_KEYSTORE_PASSWORD`, and `OPENAI_X509_CERTIFICATE_ALIAS` for this example. You can instead supply PEM-backed or hardware-backed managers to the SDK.

364 364 

guides/your-data.md +54 −178

Details

158 158 

159Web Search with live internet access is not HIPAA eligible and is not covered by a BAA. Web Search in offline/cache-only mode (`external_web_access: false`) is eligible to be covered by a BAA when used with an API key from a ZDR-enabled project within a ZDR organization. This HIPAA/BAA guidance applies only to the Responses API `web_search` tool. Note: Preview variants (`web_search_preview`) ignore this parameter and behave as if `external_web_access` is `true`. We recommend using `web_search`.159Web Search with live internet access is not HIPAA eligible and is not covered by a BAA. Web Search in offline/cache-only mode (`external_web_access: false`) is eligible to be covered by a BAA when used with an API key from a ZDR-enabled project within a ZDR organization. This HIPAA/BAA guidance applies only to the Responses API `web_search` tool. Note: Preview variants (`web_search_preview`) ignore this parameter and behave as if `external_web_access` is `true`. We recommend using `web_search`.

160 160 

161## Data residency controls161<span

162 162 id="how-does-data-residency-work"

163Data residency controls are a project configuration option that allow you to configure the location of infrastructure OpenAI uses to provide services.163 className="scroll-mt-[var(--docs-scroll-offset)]"

164 164>

165Contact our [sales team](https://openai.com/contact-sales) to see if you're eligible for using data residency controls. Data residency endpoints are charged a [10% uplift](https://developers.openai.com/api/docs/pricing) for models released on or after March 5, 2026, that are eligible for data residency.

166 

167### How does data residency work?

168 

169When data residency is enabled on your account, you can set a region for new projects you create in your account from the available regions listed below. If you use the supported endpoints, models, and snapshots listed below, your customer content (as defined in your services agreement) for that project will be stored at rest in the selected region to the extent the endpoint requires data persistence to function (such as /v1/batches).

170 

171If you select a region that supports regional processing, as specifically identified below, the services will perform inference for your Customer Content in the selected region as well.

172 

173Data residency does not apply to system data, which may be processed and stored outside the selected region. System data means account data, metadata, and usage data that do not contain Customer Content, which are collected by the services and used to manage and operate the services, such as account information or profiles of end users that directly access the services (for example, your personnel), analytics, usage statistics, billing information, support requests, and structured output schema.

174 

175### Sub-processors and regional request processing

176 

177OpenAI uses [sub-processors](https://openai.com/policies/sub-processor-list/) to provide its services. For requests sent to `us.api.openai.com` or `eu.api.openai.com`, OpenAI uses [Cloudflare Regional Services](https://developers.cloudflare.com/data-localization/regional-services/) so that TLS termination and HTTPS decryption occur within the selected processing region.

178 

179### Limitations

180 

181Data residency does not apply to: (1) any transmission or storage of Customer Content outside of the selected region caused by the location of an End User or Customer’s infrastructure when accessing the services; (2) products, services, or content offered by parties other than OpenAI through the Services; or (3) any data other than Customer Content, such as system data.

182 

183If your selected Region does not support regional processing, as identified below, OpenAI may also process and temporarily store Customer Content outside of the Region to deliver the services.

184 

185### Additional requirements for non-US regions

186 

187To use data residency with any region other than the United States, you must be approved for abuse monitoring controls, and execute a Modified Retention amendment.

188 

189Selecting the United Arab Emirates region requires additional approval. Contact [sales](https://openai.com/contact-sales) for assistance.

190 

191### How to use data residency

192 

193Data residency is configured per-project within your API Organization.

194 

195To configure data residency for regional storage, select the appropriate region from the dropdown when creating a new project.

196 

197For requests to projects with data residency configured, add the domain prefix as defined in the table below to each request.

198 

199#### Select a processing region per request

200 

201As an alternative to creating a region-specific project, you can select regional processing for an individual request by using the prefixed domain with an API key from a project having Global geography.

202 

203Existing eligibility and data retention control requirements still apply. The selected endpoint and model must also support regional processing, as shown in the table below.

204 165 

205The following example reuses one client and an API key from a Global project for global, US, and EU requests:166<span

167 id="sub-processors-and-regional-request-processing"

168 className="scroll-mt-[var(--docs-scroll-offset)]"

169>

206 170 

207```python

208from openai import OpenAI

209 171 

210client = OpenAI()

211 172 

212# No processing constraint.

213response = client.responses.create(

214 model="gpt-5.6-terra",

215 input="Reply with OK.",

216)

217print(response.output_text)

218 173 

219# US processing and storage.174<span

220response = client.with_options(175 id="additional-requirements-for-non-us-regions"

221 base_url="https://us.api.openai.com/v1",176 className="scroll-mt-[var(--docs-scroll-offset)]"

222).responses.create(177>

223 model="gpt-5.6-terra",

224 input="Reply with OK.",

225)

226print(response.output_text)

227 178 

228# EU processing and storage.179<span

229response = client.with_options(180 id="how-to-use-data-residency"

230 base_url="https://eu.api.openai.com/v1",181 className="scroll-mt-[var(--docs-scroll-offset)]"

231).responses.create(182>

232 model="gpt-5.6-terra",

233 input="Reply with OK.",

234)

235print(response.output_text)

236```

237 183 

238```ruby184<span

239require "openai"185 id="select-a-processing-region-per-request"

186 className="scroll-mt-[var(--docs-scroll-offset)]"

187>

240 188 

241client = OpenAI::Client.new189<span

190 id="which-models-and-features-are-eligible-for-data-residency"

191 className="scroll-mt-[var(--docs-scroll-offset)]"

192>

242 193 

243response = client.responses.create(194<span

244 model: "gpt-5.6-terra",195 id="support-by-region"

245 input: "Reply with OK."196 className="scroll-mt-[var(--docs-scroll-offset)]"

246)197>

247puts(response.output_text)

248 198 

249response = client.with_options(data_residency: :us).responses.create(199<span

250 model: "gpt-5.6-terra",200 id="api-endpoint-tool-and-model-support"

251 input: "Reply with OK."201 className="scroll-mt-[var(--docs-scroll-offset)]"

252)202>

253puts(response.output_text)

254 203 

255# EU processing requires a key from an EU-region project.204<span

256response = client.with_options(data_residency: :eu, api_key: ENV.fetch("OPENAI_EU_API_KEY"), organization: nil, project: nil).responses.create(205 id="endpoint-limitations"

257 model: "gpt-5.6-terra",206 className="scroll-mt-[var(--docs-scroll-offset)]"

258 input: "Reply with OK."207>

259)

260puts(response.output_text)

261```

262 208 

209<span

210 id="v1decisions-1"

211 className="scroll-mt-[var(--docs-scroll-offset)]"

212>

263 213 

264### Which models and features are eligible for data residency?214<span

215 id="v1chatcompletions-1"

216 className="scroll-mt-[var(--docs-scroll-offset)]"

217>

265 218 

266The following models and API services are eligible for data residency today for the regions specified below.219<span

220 id="v1responses-1"

221 className="scroll-mt-[var(--docs-scroll-offset)]"

222>

267 223 

268Use **Support by region** to compare regional capabilities and expand the services available in each region. Use **API Endpoint, tool and model support** for complete model lists and a detailed service view. Support for regional storage does not imply support for regional processing.224<span

225 id="v1livesessions"

226 className="scroll-mt-[var(--docs-scroll-offset)]"

227>

269 228 

270In Australia, India, and Japan, organizations with active Zero Data Retention can use `gpt-6-luna` for regional processing. These regions support Standard pay-as-you-go only. Use a project in the selected region. The Responses and Chat Completions APIs support text and image inputs and text output. Hosted tools are unavailable for regional processing in these three regions.

271 229 

272Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna. Fast mode is not available with EU data residency for GPT-6 Astra or GPT-6 Sol. GPT-6.1 Sol, GPT-6.1 Terra, GPT-6 Sol, and GPT-6 Luna support EU data residency with Standard, Flex, and Batch processing. [Ultrafast mode](https://developers.openai.com/api/docs/guides/ultrafast-mode) for GPT-6.1 Sol supports US and EU data residency and global processing. GPT-6 Astra Ultrafast supports US data residency and global processing only.

273 230 

274#### Support by region

275 231 

276The complete, unfiltered regional support table follows. Model snapshots for each service are listed in **API Endpoint, tool and model support**. When regional processing supports only a subset of snapshots, that subset is included in the processing-services cell.

277 232 

278| Region | Domain prefix | Regional storage | Regional processing | MAM or ZDR required | Supported modes | Storage services | Processing services |233## Data residency controls

279| -------------------------- | ------------------- | :--------------: | :-----------------: | :-----------------: | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

280| United States | `us.api.openai.com` | Yes | Yes | No | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/evals`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/live/sessions`<br />`/v1/realtime`<br />`/v1/realtime/transcription_sessions`<br />`/v1/realtime/translations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/evals`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/live/sessions`<br />`/v1/realtime`<br />`/v1/realtime/transcription_sessions`<br />`/v1/realtime/translations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`Code Interpreter tool`<br />`File Search`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` |

281| Europe (EEA + Switzerland) | `eu.api.openai.com` | Yes | Yes | Yes\*\* | Text, Audio, Voice, Image\* | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/evals`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/live/sessions`<br />`/v1/realtime`<br />`/v1/realtime/transcription_sessions`<br />`/v1/realtime/translations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/evals`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/live/sessions`<br />`/v1/realtime`<br />`/v1/realtime/transcription_sessions`<br />`/v1/realtime/translations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`Code Interpreter tool`<br />`File Search`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` |

282| Australia\* | `au.api.openai.com` | Yes | Yes | Yes\*\*\* | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/chat/completions` (`gpt-6-luna`)<br />`/v1/responses` (`gpt-6-luna`) |

283| Canada\* | `ca.api.openai.com` | Yes | No | Yes | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | None |

284| Japan\* | `jp.api.openai.com` | Yes | Yes | Yes\*\*\* | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/chat/completions` (`gpt-6-luna`)<br />`/v1/responses` (`gpt-6-luna`) |

285| India\* | `in.api.openai.com` | Yes | Yes | Yes\*\*\* | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/chat/completions` (`gpt-6-luna`)<br />`/v1/responses` (`gpt-6-luna`) |

286| Singapore\* | `sg.api.openai.com` | Yes | No | Yes | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | None |

287| South Korea\* | `kr.api.openai.com` | Yes | No | Yes | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | None |

288| United Kingdom\* | `gb.api.openai.com` | Yes | No | Yes | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | None |

289| United Arab Emirates\* | `ae.api.openai.com` | Yes | Yes | Yes | Text, Audio, Voice, Image | `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech`<br />`/v1/batches`<br />`/v1/chat/completions`<br />`/v1/decisions`<br />`/v1/embeddings`<br />`/v1/files`<br />`/v1/fine_tuning/jobs`<br />`/v1/images/edits`<br />`/v1/images/generations`<br />`/v1/moderations`<br />`/v1/responses`<br />`/v1/responses File Search`<br />`/v1/responses Web Search`<br />`/v1/vector_stores`<br />`Code Interpreter tool`<br />`File Search`<br />`File Uploads`<br />`Remote MCP server tool`<br />`Scale Tier`<br />`Structured Outputs (excluding schema)`<br />`Supported input modalities` | `/v1/chat/completions` (`gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.2-2025-12-11`)<br />`/v1/embeddings` (`text-embedding-3-large`)<br />`/v1/responses` (`gpt-5.5-pro-2026-04-23`, `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.2-2025-12-11`) |

290 

291\* Image support in these regions requires approval for enhanced Zero Data Retention or enhanced Modified Abuse Monitoring.

292 

293\*\* Requires Zero Data Retention, Modified Abuse Monitoring, Private Retention with PSP, or Safety Retention.

294 

295\*\*\* Regional processing in Australia, India, and Japan requires active Zero Data Retention (ZDR). Modified Abuse Monitoring (MAM) alone is insufficient.

296 

297#### API Endpoint, tool and model support

298 

299| Endpoint or feature | Service | Storage regions | Processing regions | Supported models and snapshots | Regional processing snapshot exceptions | Notes |

300| -------------------------------------------------------------------- | ---------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

301| `/v1/audio/transcriptions, /v1/audio/translations, /v1/audio/speech` | Audio | All listed regions | United States, Europe (EEA + Switzerland) | `tts-1`, `whisper-1`, `gpt-4o-tts`, `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, `gpt-transcribe` | None | — |

302| `/v1/batches` | Batches | All listed regions | United States, Europe (EEA + Switzerland) | `gpt-6-astra`, `gpt-6.1-sol`, `gpt-6.1-terra`, `gpt-6-sol`, `gpt-6-luna`, `gpt-5.5-pro-2026-04-23`, `gpt-5.4-pro-2026-03-05`, `gpt-5.2-pro-2025-12-11`, `gpt-5-pro-2025-10-06`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.4-2026-03-05`, `gpt-5-2025-08-07`, `gpt-5.4-mini-2026-03-17`, `gpt-5.4-nano-2026-03-17`, `gpt-5.2-2025-12-11`, `gpt-5.1-2025-11-13`, `gpt-5-mini-2025-08-07`, `gpt-5-nano-2025-08-07`, `gpt-4.1-2025-04-14`, `gpt-4.1-mini-2025-04-14`, `gpt-4.1-nano-2025-04-14`, `o3-2025-04-16`, `o4-mini-2025-04-16`, `o1-pro`, `o1-pro-2025-03-19`, `o3-mini-2025-01-31`, `o1-2024-12-17`, `gpt-4o-2024-11-20`, `gpt-4o-2024-08-06`, `gpt-4o-mini-2024-07-18`, `gpt-4-turbo-2024-04-09`, `gpt-4-0613`, `gpt-3.5-turbo-0125` | None | GPT-6.1 Sol, GPT-6.1 Terra, GPT-6 Sol, and GPT-6 Luna support EU data residency with Standard, Flex, and Batch processing. GPT-6.1 Sol and GPT-6.1 Terra support only US and EU data residency. |

303| `/v1/chat/completions` | Chat Completions | All listed regions | United States, Europe (EEA + Switzerland), United Arab Emirates, Australia, India, Japan | `gpt-6-astra`, `gpt-6.1-sol`, `gpt-6.1-terra`, `gpt-6-sol`, `gpt-6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.4-2026-03-05`, `gpt-5.4-mini-2026-03-17`, `gpt-5.4-nano-2026-03-17`, `gpt-5.2-2025-12-11`, `gpt-5.1-2025-11-13`, `gpt-5-2025-08-07`, `gpt-5-mini-2025-08-07`, `gpt-5-nano-2025-08-07`, `gpt-4.1-2025-04-14`, `gpt-4.1-mini-2025-04-14`, `gpt-4.1-nano-2025-04-14`, `o3-mini-2025-01-31`, `o3-2025-04-16`, `o4-mini-2025-04-16`, `o1-2024-12-17`, `gpt-4o-2024-11-20`, `gpt-4o-2024-08-06`, `gpt-4o-mini-2024-07-18`, `gpt-4-turbo-2024-04-09`, `gpt-4-0613`, `gpt-3.5-turbo-0125` | United Arab Emirates: `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.2-2025-12-11`<br />Australia, India, Japan: `gpt-6-luna` | Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna. Fast mode is not available with EU data residency for GPT-6 Astra or GPT-6 Sol. GPT-6.1 Sol and GPT-6.1 Terra support only US and EU data residency. |

304| `/v1/decisions` | Decisions | All listed regions | United States, Europe (EEA + Switzerland) | `gpt-6-luna` | None | Available in all supported API regions. Regional processing is supported in the United States and Europe (EEA + Switzerland). Prompt caching is subject to the retention limitations below. |

305| `/v1/embeddings` | Embeddings | All listed regions | United States, Europe (EEA + Switzerland), United Arab Emirates | `text-embedding-3-small`, `text-embedding-3-large`, `text-embedding-ada-002` | United Arab Emirates: `text-embedding-3-large` | — |

306| `/v1/evals` | Evals | United States, Europe (EEA + Switzerland) | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

307| `/v1/files` | Files | All listed regions | None | Service-level support | None | — |

308| `/v1/fine_tuning/jobs` | Fine-tuning | All listed regions | United States, Europe (EEA + Switzerland) | `gpt-4o-2024-08-06`, `gpt-4o-mini-2024-07-18`, `gpt-4.1-2025-04-14`, `gpt-4.1-mini-2025-04-14` | None | — |

309| `/v1/images/edits` | Images | All listed regions | United States, Europe (EEA + Switzerland) | `gpt-image-2.5-sunburst`, `gpt-image-2.5-sunburst-2026-09-08`, `gpt-image-2.5-flare`, `gpt-image-2.5-flare-2026-09-08`, `gpt-image-2`, `gpt-image-1.5`, `gpt-image-1-mini` | None | — |

310| `/v1/images/generations` | Images | All listed regions | United States, Europe (EEA + Switzerland) | `gpt-image-2.5-sunburst`, `gpt-image-2.5-sunburst-2026-09-08`, `gpt-image-2.5-flare`, `gpt-image-2.5-flare-2026-09-08`, `gpt-image-2`, `gpt-image-1.5`, `gpt-image-1-mini` | None | — |

311| `/v1/moderations` | Moderation | All listed regions | United States, Europe (EEA + Switzerland) | `omni-moderation-latest` | None | — |

312| `/v1/live/sessions` | GPT-Live | United States, Europe (EEA + Switzerland) | United States, Europe (EEA + Switzerland) | `gpt-live-1` | None | — |

313| `/v1/realtime` | Realtime | United States, Europe (EEA + Switzerland) | United States, Europe (EEA + Switzerland) | `gpt-realtime`, `gpt-realtime-1.5`, `gpt-realtime-mini`, `gpt-realtime-2`, `gpt-realtime-2.1`, `gpt-realtime-2.1-mini` | None | — |

314| `/v1/realtime/transcription_sessions` | Realtime | United States, Europe (EEA + Switzerland) | United States, Europe (EEA + Switzerland) | `gpt-realtime-whisper`, `gpt-live-transcribe`, `gpt-transcribe` | None | — |

315| `/v1/realtime/translations` | Realtime | United States, Europe (EEA + Switzerland) | United States, Europe (EEA + Switzerland) | `gpt-realtime-translate` | None | — |

316| `/v1/responses` | Responses | All listed regions | United States, Europe (EEA + Switzerland), United Arab Emirates, Australia, India, Japan | `gpt-6-astra`, `gpt-6.1-sol`, `gpt-6.1-terra`, `gpt-6-sol`, `gpt-6-luna`, `gpt-5.5-pro-2026-04-23`, `gpt-5.4-pro-2026-03-05`, `gpt-5.2-pro-2025-12-11`, `gpt-5-pro-2025-10-06`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.4-2026-03-05`, `gpt-5-2025-08-07`, `gpt-5.4-mini-2026-03-17`, `gpt-5.4-nano-2026-03-17`, `gpt-5.2-2025-12-11`, `gpt-5.1-2025-11-13`, `gpt-5-mini-2025-08-07`, `gpt-5-nano-2025-08-07`, `gpt-4.1-2025-04-14`, `gpt-4.1-mini-2025-04-14`, `gpt-4.1-nano-2025-04-14`, `o3-2025-04-16`, `o4-mini-2025-04-16`, `o1-pro`, `o1-pro-2025-03-19`, `o3-mini-2025-01-31`, `o1-2024-12-17`, `gpt-4o-2024-11-20`, `gpt-4o-2024-08-06`, `gpt-4o-mini-2024-07-18`, `gpt-4-turbo-2024-04-09`, `gpt-4-0613`, `gpt-3.5-turbo-0125` | United Arab Emirates: `gpt-5.5-pro-2026-04-23`, `gpt-5.6-luna`, `gpt-5.5-2026-04-23`, `gpt-5.2-2025-12-11`<br />Australia, India, Japan: `gpt-6-luna` | Fast mode supports EU data residency for GPT-6.1 Sol, GPT-6.1 Terra, and GPT-6 Luna. Fast mode is not available with EU data residency for GPT-6 Astra or GPT-6 Sol. GPT-6.1 Sol and GPT-6.1 Terra support only US and EU data residency. |

317| `/v1/responses File Search` | Responses | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

318| `/v1/responses Web Search` | Responses | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

319| `/v1/vector_stores` | Vector stores | All listed regions | None | Service-level support | None | — |

320| `Code Interpreter tool` | Tools | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

321| `File Search` | Tools | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

322| `File Uploads` | Files | All listed regions | None | Service-level support | None | Supported when used with base64 file uploads. |

323| `Remote MCP server tool` | Tools | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | MCP servers are third-party services. Data sent to an MCP server is subject to its data residency policies. |

324| `Scale Tier` | Other | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

325| `Structured Outputs (excluding schema)` | Other | All listed regions | United States, Europe (EEA + Switzerland) | Service-level support | None | — |

326| `Supported input modalities` | Other | All listed regions | United States, Europe (EEA + Switzerland) | `Text`, `Image`, `Audio/Voice` | None | — |

327 

328 

329 

330### Endpoint limitations

331 

332#### /v1/decisions

333 

334The Decisions API is available in all supported API regions. Regional processing is supported in the United States and Europe (EEA + Switzerland). Availability in a region does not imply that inference is performed in that region.

335 

336- [Extended prompt caching](https://developers.openai.com/api/docs/guides/prompt-caching#prompt-cache-retention) in regions that do not support Regional processing may require that OpenAI process and temporarily store Customer Content outside of the Region to deliver the services.

337 

338#### /v1/chat/completions

339 

340- Cannot set store=true in non-US regions.

341- [Extended prompt caching](https://developers.openai.com/api/docs/guides/prompt-caching#prompt-cache-retention) in regions that do not support Regional processing may require that OpenAI process and temporarily store Customer Content outside of the Region to deliver the services.

342 

343#### /v1/responses

344 

345- [Extended prompt caching](https://developers.openai.com/api/docs/guides/prompt-caching#prompt-cache-retention) in regions that do not support Regional processing may require that OpenAI process and temporarily store Customer Content outside of the Region to deliver the services.

346 

347#### /v1/live/sessions

348 

349GPT-Live sessions are eligible for Zero Data Retention. With Zero Data Retention enabled, `store` is treated as `false`, even if a request sets it to `true`.

350 

351Session storage is disabled by default. For projects with session storage enabled, `store: true` retains the completed session recording for 30 days so that it can be downloaded or used to start a forked session. Stored sessions and their index expire after 30 days. Recording downloads and forking require a data policy that permits persistence and are not available with Zero Data Retention.

352 

353Setting `store: false` on a fork prevents storage of the new session; it does not delete the source recording or remove the authorization required to read it. The API does not provide a public stored-session deletion endpoint.

354 

355GPT-Live supports data residency in the United States and Europe. Delegated backend models and tools have their own data controls; check the applicable endpoint and feature entries on this page.

356 

357#### /v1/realtime

358 234 

359Tracing is not currently EU data residency compliant for `/v1/realtime`.235See the [Data residency guide](https://developers.openai.com/api/docs/guides/data-residency) for regional storage and processing options, eligibility, setup instructions, and supported models and endpoints.

360 236 

361## Enterprise Key Management (EKM)237## Enterprise Key Management (EKM)

362 238 

libraries.md +10 −8

Details

39 39 

40 40 

41 41 

42JavaScript42TypeScript

43 43 

44 44

45 45 

46To use the OpenAI API in server-side JavaScript environments like Node.js, Deno, or Bun, you can use the official [OpenAI SDK for TypeScript and JavaScript](https://github.com/openai/openai-node). Get started by installing the SDK using [npm](https://www.npmjs.com/) or your preferred package manager:46To use the OpenAI API in TypeScript applications running on Node.js, Deno, or Bun, you can use the official [OpenAI SDK for TypeScript](https://github.com/openai/openai-node). The same `openai` package also supports plain JavaScript. Get started by installing the SDK using [npm](https://www.npmjs.com/) or your preferred package manager:

47 47 

48Install the OpenAI SDK with npm48Install the OpenAI SDK with npm

49 49 


53 53 

54 54 

55 55 

56With the OpenAI SDK installed, create a file called `example.mjs` and copy the example code into it:56With the OpenAI SDK installed, create a file called `example.mts` and copy the example code into it. The `.mts` extension makes this TypeScript file an ES module, including in CommonJS projects:

57 57 

58Test a basic API request58Test a basic API request

59 59 

60```javascript60```typescript

61import OpenAI from "openai";61import OpenAI from "openai";

62const client = new OpenAI();62const client = new OpenAI();

63 63 


71 71 

72 72 

73 73 

74Execute the code with `node example.mjs` (or the equivalent command for Deno or Bun). In a few moments, you should see the output of your API request.74Execute the code with `node --experimental-strip-types example.mts` on Node.js 22.6 or later (or use the equivalent command for Deno or Bun). In a few moments, you should see the output of your API request.

75 

76To run this example as plain JavaScript, save the same code as `example.mjs` and run `node example.mjs`.

75 77 

76[Learn more on GitHub](https://github.com/openai/openai-node)78[Learn more on GitHub](https://github.com/openai/openai-node)

77 79 


175<dependency>177<dependency>

176 <groupId>com.openai</groupId>178 <groupId>com.openai</groupId>

177 <artifactId>openai-java</artifactId>179 <artifactId>openai-java</artifactId>

178 <version>4.104.0</version>180 <version>4.105.0</version>

179</dependency>181</dependency>

180```182```

181 183 


392 394 

393### Dart/Flutter395### Dart/Flutter

394 396 

395- [openai](https://github.com/anasfik/openai) by [anasfik](https://github.com/anasfik)397- [`openai`](https://github.com/anasfik/openai) by [anasfik](https://github.com/anasfik)

396 398 

397### Delphi399### Delphi

398 400 


436## Other OpenAI repositories438## Other OpenAI repositories

437 439 

438- [tiktoken](https://github.com/openai/tiktoken) - counting tokens440- [tiktoken](https://github.com/openai/tiktoken) - counting tokens

439- [simple-evals](https://github.com/openai/simple-evals) - simple evaluation library441- [`simple-evals`](https://github.com/openai/simple-evals): evaluation library

440- [mle-bench](https://github.com/openai/mle-bench) - library to evaluate machine learning engineer agents442- [mle-bench](https://github.com/openai/mle-bench) - library to evaluate machine learning engineer agents

441- [gym](https://github.com/openai/gym) - reinforcement learning library443- [gym](https://github.com/openai/gym) - reinforcement learning library

442- [swarm](https://github.com/openai/swarm) - educational orchestration repository444- [swarm](https://github.com/openai/swarm) - educational orchestration repository

quickstart.md +19 −17

Details

49 49 

50 50 

51 51 

52JavaScript52TypeScript

53 53 

54 54

55 55 

56To use the OpenAI API in server-side JavaScript environments like Node.js, Deno, or Bun, you can use the official [OpenAI SDK for TypeScript and JavaScript](https://github.com/openai/openai-node). Get started by installing the SDK using [npm](https://www.npmjs.com/) or your preferred package manager:56To use the OpenAI API in TypeScript applications running on Node.js, Deno, or Bun, you can use the official [OpenAI SDK for TypeScript](https://github.com/openai/openai-node). The same `openai` package also supports plain JavaScript. Get started by installing the SDK using [npm](https://www.npmjs.com/) or your preferred package manager:

57 57 

58Install the OpenAI SDK with npm58Install the OpenAI SDK with npm

59 59 


63 63 

64 64 

65 65 

66With the OpenAI SDK installed, create a file called `example.mjs` and copy the example code into it:66With the OpenAI SDK installed, create a file called `example.mts` and copy the example code into it. The `.mts` extension makes this TypeScript file an ES module, including in CommonJS projects:

67 67 

68Test a basic API request68Test a basic API request

69 69 

70```javascript70```typescript

71import OpenAI from "openai";71import OpenAI from "openai";

72const client = new OpenAI();72const client = new OpenAI();

73 73 


81 81 

82 82 

83 83 

84Execute the code with `node example.mjs` (or the equivalent command for Deno or Bun). In a few moments, you should see the output of your API request.84Execute the code with `node --experimental-strip-types example.mts` on Node.js 22.6 or later (or use the equivalent command for Deno or Bun). In a few moments, you should see the output of your API request.

85 

86To run this example as plain JavaScript, save the same code as `example.mjs` and run `node example.mjs`.

85 87 

86[Learn more on GitHub](https://github.com/openai/openai-node)88[Learn more on GitHub](https://github.com/openai/openai-node)

87 89 


185<dependency>187<dependency>

186 <groupId>com.openai</groupId>188 <groupId>com.openai</groupId>

187 <artifactId>openai-java</artifactId>189 <artifactId>openai-java</artifactId>

188 <version>4.104.0</version>190 <version>4.105.0</version>

189</dependency>191</dependency>

190```192```

191 193 


365 367 

366 Analyze the content of an image368 Analyze the content of an image

367 369 

368```javascript370```typescript

369import OpenAI from "openai";371import OpenAI from "openai";

370const client = new OpenAI();372const client = new OpenAI();

371 373 


590 592 

591 Use a file URL as input593 Use a file URL as input

592 594 

593```javascript595```typescript

594import OpenAI from "openai";596import OpenAI from "openai";

595const client = new OpenAI();597const client = new OpenAI();

596 598 


808 810 

809 Upload a file and use it as input811 Upload a file and use it as input

810 812 

811```javascript813```typescript

812import fs from "fs";814import fs from "fs";

813import OpenAI from "openai";815import OpenAI from "openai";

814const client = new OpenAI();816const client = new OpenAI();


1087 1089 

1088 Use web search in a response1090 Use web search in a response

1089 1091 

1090```javascript1092```typescript

1091import OpenAI from "openai";1093import OpenAI from "openai";

1092const client = new OpenAI();1094const client = new OpenAI();

1093 1095 


1224 1226 

1225 Search your files in a response1227 Search your files in a response

1226 1228 

1227```javascript1229```typescript

1228import OpenAI from "openai";1230import OpenAI from "openai";

1229const openai = new OpenAI();1231const openai = new OpenAI();

1230 1232 


1350 1352 

1351 Use Code Interpreter in a response1353 Use Code Interpreter in a response

1352 1354 

1353```javascript1355```typescript

1354import OpenAI from "openai";1356import OpenAI from "openai";

1355const client = new OpenAI();1357const client = new OpenAI();

1356 1358 


1508 1510 

1509 Call your own function1511 Call your own function

1510 1512 

1511```javascript1513```typescript

1512import OpenAI from "openai";1514import OpenAI from "openai";

1513const client = new OpenAI();1515const client = new OpenAI();

1514 1516 

1515const tools = [1517const tools: OpenAI.Responses.Tool[] = [

1516 {1518 {

1517 type: "function",1519 type: "function",

1518 name: "get_weather",1520 name: "get_weather",


1817 }'1819 }'

1818```1820```

1819 1821 

1820```javascript1822```typescript

1821import OpenAI from "openai";1823import OpenAI from "openai";

1822const client = new OpenAI();1824const client = new OpenAI();

1823 1825 


1982 1984 

1983Stream server-sent events from the API1985Stream server-sent events from the API

1984 1986 

1985```javascript1987```typescript

1986import { OpenAI } from "openai";1988import { OpenAI } from "openai";

1987const client = new OpenAI();1989const client = new OpenAI();

1988 1990 


2126 2128 

2127Build a language triage agent2129Build a language triage agent

2128 2130 

2129```javascript2131```typescript

2130import { Agent, run } from "@openai/agents";2132import { Agent, run } from "@openai/agents";

2131 2133 

2132const spanishAgent = new Agent({2134const spanishAgent = new Agent({

Details

49 49 

50Define a helper that opens the recording and sends the file contents to [`gpt-transcribe`](https://developers.openai.com/api/docs/models/gpt-transcribe):50Define a helper that opens the recording and sends the file contents to [`gpt-transcribe`](https://developers.openai.com/api/docs/models/gpt-transcribe):

51 51 

52```javascript52```typescript

53import fs from "node:fs";53import fs from "node:fs";

54 54 

55import { Document, HeadingLevel, Packer, Paragraph, TextRun } from "docx";55import { Document, HeadingLevel, Packer, Paragraph, TextRun } from "docx";


57 57 

58const openai = new OpenAI();58const openai = new OpenAI();

59 59 

60async function transcribeAudio(audioFilePath) {60async function transcribeAudio(audioFilePath: fs.PathLike) {

61 const transcription = await openai.audio.transcriptions.create({61 const transcription = await openai.audio.transcriptions.create({

62 file: fs.createReadStream(audioFilePath),62 file: fs.createReadStream(audioFilePath),

63 model: "gpt-transcribe",63 model: "gpt-transcribe",


194 194 

195Define the shared helper that sends the transcript and task-specific instructions to the model:195Define the shared helper that sends the transcript and task-specific instructions to the model:

196 196 

197```javascript197```typescript

198async function complete(transcription, instructions) {198async function complete(transcription: string, instructions: string) {

199 const response = await openai.chat.completions.create({199 const response = await openai.chat.completions.create({

200 model: "gpt-5.5",200 model: "gpt-5.5",

201 messages: [201 messages: [


273 273 

274Define an orchestration helper that returns the four sections of the meeting minutes:274Define an orchestration helper that returns the four sections of the meeting minutes:

275 275 

276```javascript276```typescript

277async function buildMeetingMinutes(transcription) {277async function buildMeetingMinutes(transcription: string) {

278 return {278 return {

279 "Abstract summary": await extractAbstractSummary(transcription),279 "Abstract summary": await extractAbstractSummary(transcription),

280 "Key points": await extractKeyPoints(transcription),280 "Key points": await extractKeyPoints(transcription),


346 346 

347The summary helper asks the model for one concise paragraph that preserves important decisions and context while omitting tangents. The system message controls this behavior. For more ways to shape the result, see the [prompt engineering guide](https://developers.openai.com/api/docs/guides/prompt-engineering).347The summary helper asks the model for one concise paragraph that preserves important decisions and context while omitting tangents. The system message controls this behavior. For more ways to shape the result, see the [prompt engineering guide](https://developers.openai.com/api/docs/guides/prompt-engineering).

348 348 

349```javascript349```typescript

350async function extractAbstractSummary(transcription) {350async function extractAbstractSummary(transcription: string) {

351 return complete(351 return complete(

352 transcription,352 transcription,

353 "Summarize the meeting transcript in one concise paragraph. Keep the most important decisions and context, and omit tangents."353 "Summarize the meeting transcript in one concise paragraph. Keep the most important decisions and context, and omit tangents."


394 394 

395The key-points helper lists the important ideas, findings, and topics discussed in the meeting. Add relevant project or company context to the system message when it helps the model identify what matters to your audience.395The key-points helper lists the important ideas, findings, and topics discussed in the meeting. Add relevant project or company context to the system message when it helps the model identify what matters to your audience.

396 396 

397```javascript397```typescript

398async function extractKeyPoints(transcription) {398async function extractKeyPoints(transcription: string) {

399 return complete(399 return complete(

400 transcription,400 transcription,

401 "List the most important ideas, findings, and topics from the meeting. Use concise bullet points."401 "List the most important ideas, findings, and topics from the meeting. Use concise bullet points."


442 442 

443The action-items helper identifies tasks and follow-ups, including owners and deadlines when the transcript provides them. To create and assign tasks in another system, connect this step to [function calling](https://developers.openai.com/api/docs/guides/function-calling).443The action-items helper identifies tasks and follow-ups, including owners and deadlines when the transcript provides them. To create and assign tasks in another system, connect this step to [function calling](https://developers.openai.com/api/docs/guides/function-calling).

444 444 

445```javascript445```typescript

446async function extractActionItems(transcription) {446async function extractActionItems(transcription: string) {

447 return complete(447 return complete(

448 transcription,448 transcription,

449 "List every task or follow-up agreed to in the meeting. Include the owner and deadline when the transcript provides them."449 "List every task or follow-up agreed to in the meeting. Include the owner and deadline when the transcript provides them."


490 490 

491The sentiment helper classifies the discussion as positive, negative, or neutral and explains the assessment. For simpler tasks, try [`gpt-5.6-terra`](https://developers.openai.com/api/docs/models/gpt-5.6-terra) to see whether it meets your quality target with lower cost and latency.491The sentiment helper classifies the discussion as positive, negative, or neutral and explains the assessment. For simpler tasks, try [`gpt-5.6-terra`](https://developers.openai.com/api/docs/models/gpt-5.6-terra) to see whether it meets your quality target with lower cost and latency.

492 492 

493```javascript493```typescript

494async function analyzeSentiment(transcription) {494async function analyzeSentiment(transcription: string) {

495 return complete(495 return complete(

496 transcription,496 transcription,

497 "Describe the meeting's overall sentiment as positive, negative, or neutral, and briefly explain the assessment."497 "Describe the meeting's overall sentiment as positive, negative, or neutral, and briefly explain the assessment."


557 557 

558Define a helper that writes each result section to a Word document:558Define a helper that writes each result section to a Word document:

559 559 

560```javascript560```typescript

561async function saveAsDocx(minutes, filename) {561async function saveAsDocx(minutes: Record<string, string>, filename: string) {

562 const children = Object.entries(minutes).flatMap(([heading, content]) => [562 const children = Object.entries(minutes).flatMap(([heading, content]) => [

563 new Paragraph({ text: heading, heading: HeadingLevel.HEADING_1 }),563 new Paragraph({ text: heading, heading: HeadingLevel.HEADING_1 }),

564 new Paragraph({564 new Paragraph({


659 659 

660Finally, combine the steps to generate meeting minutes from an audio file:660Finally, combine the steps to generate meeting minutes from an audio file:

661 661 

662```javascript662```typescript

663const transcription = await transcribeAudio("meeting.wav");663const transcription = await transcribeAudio("meeting.wav");

664const minutes = await buildMeetingMinutes(transcription);664const minutes = await buildMeetingMinutes(transcription);

665console.log(minutes);665console.log(minutes);