From 9c2ac47e693d4d9a7206f7a69e7ed035607461e1 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 2 Oct 2025 20:13:22 +0000
Subject: [PATCH 1/2] feat(api): add support for realtime calls
---
.stats.yml | 8 +-
MIGRATION.md | 1 +
api.md | 9 +
scripts/detect-breaking-changes | 1 +
src/resources/realtime/calls.ts | 204 +++++++++++++++++++++
src/resources/realtime/client-secrets.ts | 6 +
src/resources/realtime/index.ts | 1 +
src/resources/realtime/realtime.ts | 11 ++
tests/api-resources/realtime/calls.test.ts | 98 ++++++++++
9 files changed, 335 insertions(+), 4 deletions(-)
create mode 100644 src/resources/realtime/calls.ts
create mode 100644 tests/api-resources/realtime/calls.test.ts
diff --git a/.stats.yml b/.stats.yml
index 27f2ffc6d..4e40d470f 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 118
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-e205b1f2da6a1f2caa229efa9ede63f2d3d2fedeeb2dd6ed3d880bafdcb0ab88.yml
-openapi_spec_hash: c8aee2469a749f6a838b40c57e4b7b06
-config_hash: 45dcba51451ba532959c020a0ddbf23c
+configured_endpoints: 122
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-fadefdc7c7e30df47c09df323669b242ff90ee08e51f304175ace5274e0aab49.yml
+openapi_spec_hash: 6d20f639d9ff8a097a34962da6218231
+config_hash: 902654e60f5d659f2bfcfd903e17c46d
diff --git a/MIGRATION.md b/MIGRATION.md
index 3fb14f8bc..96f665c17 100644
--- a/MIGRATION.md
+++ b/MIGRATION.md
@@ -133,6 +133,7 @@ client.example.list(undefined, { headers: { ... } });
- `client.batches.list()`
- `client.responses.retrieve()`
- `client.responses.inputItems.list()`
+- `client.realtime.calls.reject()`
- `client.conversations.create()`
- `client.conversations.items.list()`
- `client.evals.list()`
diff --git a/api.md b/api.md
index 6316bfeb3..b6e346562 100644
--- a/api.md
+++ b/api.md
@@ -897,6 +897,15 @@ Methods:
- client.realtime.clientSecrets.create({ ...params }) -> ClientSecretCreateResponse
+## Calls
+
+Methods:
+
+- client.realtime.calls.accept(callID, { ...params }) -> void
+- client.realtime.calls.hangup(callID) -> void
+- client.realtime.calls.refer(callID, { ...params }) -> void
+- client.realtime.calls.reject(callID, { ...params }) -> void
+
# Conversations
Types:
diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes
index 85607de43..4f79a5486 100755
--- a/scripts/detect-breaking-changes
+++ b/scripts/detect-breaking-changes
@@ -46,6 +46,7 @@ TEST_PATHS=(
tests/api-resources/responses/input-items.test.ts
tests/api-resources/realtime/realtime.test.ts
tests/api-resources/realtime/client-secrets.test.ts
+ tests/api-resources/realtime/calls.test.ts
tests/api-resources/conversations/conversations.test.ts
tests/api-resources/conversations/items.test.ts
tests/api-resources/evals/evals.test.ts
diff --git a/src/resources/realtime/calls.ts b/src/resources/realtime/calls.ts
new file mode 100644
index 000000000..089855fc2
--- /dev/null
+++ b/src/resources/realtime/calls.ts
@@ -0,0 +1,204 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../core/resource';
+import * as RealtimeAPI from './realtime';
+import * as ResponsesAPI from '../responses/responses';
+import { APIPromise } from '../../core/api-promise';
+import { buildHeaders } from '../../internal/headers';
+import { RequestOptions } from '../../internal/request-options';
+import { path } from '../../internal/utils/path';
+
+export class Calls extends APIResource {
+ /**
+ * Accept an incoming SIP call and configure the realtime session that will handle
+ * it.
+ *
+ * @example
+ * ```ts
+ * await client.realtime.calls.accept('call_id', {
+ * type: 'realtime',
+ * });
+ * ```
+ */
+ accept(callID: string, body: CallAcceptParams, options?: RequestOptions): APIPromise {
+ return this._client.post(path`/realtime/calls/${callID}/accept`, {
+ body,
+ ...options,
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
+ });
+ }
+
+ /**
+ * End an active Realtime API call, whether it was initiated over SIP or WebRTC.
+ *
+ * @example
+ * ```ts
+ * await client.realtime.calls.hangup('call_id');
+ * ```
+ */
+ hangup(callID: string, options?: RequestOptions): APIPromise {
+ return this._client.post(path`/realtime/calls/${callID}/hangup`, {
+ ...options,
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
+ });
+ }
+
+ /**
+ * Transfer an active SIP call to a new destination using the SIP REFER verb.
+ *
+ * @example
+ * ```ts
+ * await client.realtime.calls.refer('call_id', {
+ * target_uri: 'tel:+14155550123',
+ * });
+ * ```
+ */
+ refer(callID: string, body: CallReferParams, options?: RequestOptions): APIPromise {
+ return this._client.post(path`/realtime/calls/${callID}/refer`, {
+ body,
+ ...options,
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
+ });
+ }
+
+ /**
+ * Decline an incoming SIP call by returning a SIP status code to the caller.
+ *
+ * @example
+ * ```ts
+ * await client.realtime.calls.reject('call_id');
+ * ```
+ */
+ reject(
+ callID: string,
+ body: CallRejectParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.post(path`/realtime/calls/${callID}/reject`, {
+ body,
+ ...options,
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
+ });
+ }
+}
+
+export interface CallAcceptParams {
+ /**
+ * The type of session to create. Always `realtime` for the Realtime API.
+ */
+ type: 'realtime';
+
+ /**
+ * Configuration for input and output audio.
+ */
+ audio?: RealtimeAPI.RealtimeAudioConfig;
+
+ /**
+ * Additional fields to include in server outputs.
+ *
+ * `item.input_audio_transcription.logprobs`: Include logprobs for input audio
+ * transcription.
+ */
+ include?: Array<'item.input_audio_transcription.logprobs'>;
+
+ /**
+ * The default system instructions (i.e. system message) prepended to model calls.
+ * This field allows the client to guide the model on desired responses. The model
+ * can be instructed on response content and format, (e.g. "be extremely succinct",
+ * "act friendly", "here are examples of good responses") and on audio behavior
+ * (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The
+ * instructions are not guaranteed to be followed by the model, but they provide
+ * guidance to the model on the desired behavior.
+ *
+ * Note that the server sets default instructions which will be used if this field
+ * is not set and are visible in the `session.created` event at the start of the
+ * session.
+ */
+ instructions?: string;
+
+ /**
+ * Maximum number of output tokens for a single assistant response, inclusive of
+ * tool calls. Provide an integer between 1 and 4096 to limit output tokens, or
+ * `inf` for the maximum available tokens for a given model. Defaults to `inf`.
+ */
+ max_output_tokens?: number | 'inf';
+
+ /**
+ * The Realtime model used for this session.
+ */
+ model?:
+ | (string & {})
+ | 'gpt-realtime'
+ | 'gpt-realtime-2025-08-28'
+ | 'gpt-4o-realtime-preview'
+ | 'gpt-4o-realtime-preview-2024-10-01'
+ | 'gpt-4o-realtime-preview-2024-12-17'
+ | 'gpt-4o-realtime-preview-2025-06-03'
+ | 'gpt-4o-mini-realtime-preview'
+ | 'gpt-4o-mini-realtime-preview-2024-12-17';
+
+ /**
+ * The set of modalities the model can respond with. It defaults to `["audio"]`,
+ * indicating that the model will respond with audio plus a transcript. `["text"]`
+ * can be used to make the model respond with text only. It is not possible to
+ * request both `text` and `audio` at the same time.
+ */
+ output_modalities?: Array<'text' | 'audio'>;
+
+ /**
+ * Reference to a prompt template and its variables.
+ * [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts).
+ */
+ prompt?: ResponsesAPI.ResponsePrompt | null;
+
+ /**
+ * How the model chooses tools. Provide one of the string modes or force a specific
+ * function/MCP tool.
+ */
+ tool_choice?: RealtimeAPI.RealtimeToolChoiceConfig;
+
+ /**
+ * Tools available to the model.
+ */
+ tools?: RealtimeAPI.RealtimeToolsConfig;
+
+ /**
+ * Realtime API can write session traces to the
+ * [Traces Dashboard](/logs?api=traces). Set to null to disable tracing. Once
+ * tracing is enabled for a session, the configuration cannot be modified.
+ *
+ * `auto` will create a trace for the session with default values for the workflow
+ * name, group id, and metadata.
+ */
+ tracing?: RealtimeAPI.RealtimeTracingConfig | null;
+
+ /**
+ * Controls how the realtime conversation is truncated prior to model inference.
+ * The default is `auto`.
+ */
+ truncation?: RealtimeAPI.RealtimeTruncation;
+}
+
+export interface CallReferParams {
+ /**
+ * URI that should appear in the SIP Refer-To header. Supports values like
+ * `tel:+14155550123` or `sip:agent@example.com`.
+ */
+ target_uri: string;
+}
+
+export interface CallRejectParams {
+ /**
+ * SIP response code to send back to the caller. Defaults to `603` (Decline) when
+ * omitted.
+ */
+ status_code?: number;
+}
+
+export declare namespace Calls {
+ export {
+ type CallAcceptParams as CallAcceptParams,
+ type CallReferParams as CallReferParams,
+ type CallRejectParams as CallRejectParams,
+ };
+}
diff --git a/src/resources/realtime/client-secrets.ts b/src/resources/realtime/client-secrets.ts
index 70abeabbf..6289663fe 100644
--- a/src/resources/realtime/client-secrets.ts
+++ b/src/resources/realtime/client-secrets.ts
@@ -10,6 +10,12 @@ import { RequestOptions } from '../../internal/request-options';
export class ClientSecrets extends APIResource {
/**
* Create a Realtime client secret with an associated session configuration.
+ *
+ * @example
+ * ```ts
+ * const clientSecret =
+ * await client.realtime.clientSecrets.create();
+ * ```
*/
create(body: ClientSecretCreateParams, options?: RequestOptions): APIPromise {
return this._client.post('/realtime/client_secrets', { body, ...options });
diff --git a/src/resources/realtime/index.ts b/src/resources/realtime/index.ts
index 777543853..197aa3b56 100644
--- a/src/resources/realtime/index.ts
+++ b/src/resources/realtime/index.ts
@@ -1,5 +1,6 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+export { Calls, type CallAcceptParams, type CallReferParams, type CallRejectParams } from './calls';
export {
ClientSecrets,
type RealtimeSessionClientSecret,
diff --git a/src/resources/realtime/realtime.ts b/src/resources/realtime/realtime.ts
index 739d61a54..49d22a39d 100644
--- a/src/resources/realtime/realtime.ts
+++ b/src/resources/realtime/realtime.ts
@@ -3,6 +3,8 @@
import { APIResource } from '../../core/resource';
import * as RealtimeAPI from './realtime';
import * as Shared from '../shared';
+import * as CallsAPI from './calls';
+import { CallAcceptParams, CallReferParams, CallRejectParams, Calls } from './calls';
import * as ClientSecretsAPI from './client-secrets';
import {
ClientSecretCreateParams,
@@ -17,6 +19,7 @@ import * as ResponsesAPI from '../responses/responses';
export class Realtime extends APIResource {
clientSecrets: ClientSecretsAPI.ClientSecrets = new ClientSecretsAPI.ClientSecrets(this._client);
+ calls: CallsAPI.Calls = new CallsAPI.Calls(this._client);
}
export interface AudioTranscription {
@@ -4580,6 +4583,7 @@ export namespace TranscriptionSessionUpdatedEvent {
}
Realtime.ClientSecrets = ClientSecrets;
+Realtime.Calls = Calls;
export declare namespace Realtime {
export {
@@ -4694,4 +4698,11 @@ export declare namespace Realtime {
type ClientSecretCreateResponse as ClientSecretCreateResponse,
type ClientSecretCreateParams as ClientSecretCreateParams,
};
+
+ export {
+ Calls as Calls,
+ type CallAcceptParams as CallAcceptParams,
+ type CallReferParams as CallReferParams,
+ type CallRejectParams as CallRejectParams,
+ };
}
diff --git a/tests/api-resources/realtime/calls.test.ts b/tests/api-resources/realtime/calls.test.ts
new file mode 100644
index 000000000..34675a134
--- /dev/null
+++ b/tests/api-resources/realtime/calls.test.ts
@@ -0,0 +1,98 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import OpenAI from 'openai';
+
+const client = new OpenAI({
+ apiKey: 'My API Key',
+ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010',
+});
+
+describe('resource calls', () => {
+ test('accept: only required params', async () => {
+ const responsePromise = client.realtime.calls.accept('call_id', { type: 'realtime' });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ test('accept: required and optional params', async () => {
+ const response = await client.realtime.calls.accept('call_id', {
+ type: 'realtime',
+ audio: {
+ input: {
+ format: { rate: 24000, type: 'audio/pcm' },
+ noise_reduction: { type: 'near_field' },
+ transcription: { language: 'language', model: 'whisper-1', prompt: 'prompt' },
+ turn_detection: {
+ type: 'server_vad',
+ create_response: true,
+ idle_timeout_ms: 5000,
+ interrupt_response: true,
+ prefix_padding_ms: 0,
+ silence_duration_ms: 0,
+ threshold: 0,
+ },
+ },
+ output: { format: { rate: 24000, type: 'audio/pcm' }, speed: 0.25, voice: 'ash' },
+ },
+ include: ['item.input_audio_transcription.logprobs'],
+ instructions: 'instructions',
+ max_output_tokens: 0,
+ model: 'string',
+ output_modalities: ['text'],
+ prompt: { id: 'id', variables: { foo: 'string' }, version: 'version' },
+ tool_choice: 'none',
+ tools: [{ description: 'description', name: 'name', parameters: {}, type: 'function' }],
+ tracing: 'auto',
+ truncation: 'auto',
+ });
+ });
+
+ test('hangup', async () => {
+ const responsePromise = client.realtime.calls.hangup('call_id');
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ test('refer: only required params', async () => {
+ const responsePromise = client.realtime.calls.refer('call_id', { target_uri: 'tel:+14155550123' });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ test('refer: required and optional params', async () => {
+ const response = await client.realtime.calls.refer('call_id', { target_uri: 'tel:+14155550123' });
+ });
+
+ test('reject', async () => {
+ const responsePromise = client.realtime.calls.reject('call_id');
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ test('reject: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.realtime.calls.reject('call_id', { status_code: 486 }, { path: '/_stainless_unknown_path' }),
+ ).rejects.toThrow(OpenAI.NotFoundError);
+ });
+});
From 49fe03d696a73b8d0be50d3fa85fc7d5e704d50d Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 2 Oct 2025 20:13:52 +0000
Subject: [PATCH 2/2] release: 6.1.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 8 ++++++++
jsr.json | 2 +-
package.json | 2 +-
src/version.ts | 2 +-
5 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 601e9bed3..8ace91523 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "6.0.1"
+ ".": "6.1.0"
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fdeefbe85..c9e656df0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## 6.1.0 (2025-10-02)
+
+Full Changelog: [v6.0.1...v6.1.0](https://github.com/openai/openai-node/compare/v6.0.1...v6.1.0)
+
+### Features
+
+* **api:** add support for realtime calls ([5de9585](https://github.com/openai/openai-node/commit/5de958556679182dfbdce95b4db6b65ca742aa61))
+
## 6.0.1 (2025-10-01)
Full Changelog: [v6.0.0...v6.0.1](https://github.com/openai/openai-node/compare/v6.0.0...v6.0.1)
diff --git a/jsr.json b/jsr.json
index 0a4195e83..a7819c2ba 100644
--- a/jsr.json
+++ b/jsr.json
@@ -1,6 +1,6 @@
{
"name": "@openai/openai",
- "version": "6.0.1",
+ "version": "6.1.0",
"exports": {
".": "./index.ts",
"./helpers/zod": "./helpers/zod.ts",
diff --git a/package.json b/package.json
index 892c6f29d..fc7599145 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "openai",
- "version": "6.0.1",
+ "version": "6.1.0",
"description": "The official TypeScript library for the OpenAI API",
"author": "OpenAI ",
"types": "dist/index.d.ts",
diff --git a/src/version.ts b/src/version.ts
index be1e964c4..444aa7c72 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1 +1 @@
-export const VERSION = '6.0.1'; // x-release-please-version
+export const VERSION = '6.1.0'; // x-release-please-version