OpenAI Free code examples in C#, Python, Java and JavaScript
GPT models, function calling, structured outputs and the Responses API.
Try it without writing code: Prompt Generator, Prompt Testing Kit — free in the browser.
WHAT THIS PAGE COVERS
A chat call with streaming, then the same call with a tool the model can invoke.
gpt-5.4-mini
openai
Model ids change. If a sample returns a 404 on the model, that is the first thing to check against the official docs.
The official OpenAI package for .NET. One ChatClient is bound to one model — different from the other SDKs on this page, where the model is a per-call argument.
dotnet add package OpenAI
setx OPENAI_API_KEY "sk-..."
Register ChatClient as a singleton in DI rather than newing one per request. It owns an HttpClient, and one per request will exhaust your sockets under load.
using OpenAI.Chat;
ChatClient client = new(
model: "gpt-5.4-mini",
apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
ChatCompletion completion = await client.CompleteChatAsync(
[
new SystemChatMessage("You are a concise technical assistant."),
new UserChatMessage("Explain a database index in two sentences."),
]);
Console.WriteLine(completion.Content[0].Text);
Console.WriteLine($"{completion.Usage.InputTokenCount} in, {completion.Usage.OutputTokenCount} out");
ContentUpdate is a list, not a string — one update can carry several parts, and many carry none at all.
using OpenAI.Chat;
await foreach (StreamingChatCompletionUpdate update
in client.CompleteChatStreamingAsync(
[new UserChatMessage("Write a haiku about indexes.")]))
{
foreach (ChatMessageContentPart part in update.ContentUpdate)
{
Console.Write(part.Text);
}
}
Console.WriteLine();
Parameters are raw JSON Schema via BinaryData. Keep the schema and the C# method beside each other — a description that drifts from the implementation is the usual reason a model stops calling a tool.
using System.Text.Json;
using OpenAI.Chat;
static string GetWeather(string city) =>
JsonSerializer.Serialize(new { city, celsius = 29, sky = "clear" });
ChatTool weatherTool = ChatTool.CreateFunctionTool(
functionName: "get_weather",
functionDescription: "Current weather for a city.",
functionParameters: BinaryData.FromString("""
{
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
"""));
List<ChatMessage> messages = [new UserChatMessage("What is the weather in Delhi?")];
ChatCompletionOptions options = new() { Tools = { weatherTool } };
ChatCompletion first = await client.CompleteChatAsync(messages, options);
messages.Add(new AssistantChatMessage(first));
foreach (ChatToolCall call in first.ToolCalls)
{
using JsonDocument args = JsonDocument.Parse(call.FunctionArguments);
string city = args.RootElement.GetProperty("city").GetString()!;
messages.Add(new ToolChatMessage(call.Id, GetWeather(city)));
}
ChatCompletion second = await client.CompleteChatAsync(messages, options);
Console.WriteLine(second.Content[0].Text);
ClientResultException carries the HTTP status. Branch on that rather than on the message, and check FinishReason before you trust the text.
using System.ClientModel;
using OpenAI.Chat;
try
{
ChatCompletion completion = await client.CompleteChatAsync(
[new UserChatMessage("...")],
new ChatCompletionOptions { MaxOutputTokenCount = 1000 });
if (completion.FinishReason == ChatFinishReason.Length)
{
Console.WriteLine("Truncated — raise MaxOutputTokenCount.");
}
}
catch (ClientResultException ex) when (ex.Status == 401)
{
Console.Error.WriteLine("OPENAI_API_KEY missing or revoked.");
}
catch (ClientResultException ex) when (ex.Status == 404)
{
Console.Error.WriteLine("Unknown model id — check the official docs linked below.");
}
catch (ClientResultException ex) when (ex.Status == 429)
{
Console.Error.WriteLine("Rate limited or out of quota.");
}
catch (ClientResultException ex)
{
Console.Error.WriteLine($"API error {ex.Status}: {ex.Message}");
}
The client reads OPENAI_API_KEY from the environment. Keep it there — a key in source is a key in your git history, and rotating it is the only fix.
pip install openai
export OPENAI_API_KEY="sk-..." # macOS / Linux
setx OPENAI_API_KEY "sk-..." # Windows, then open a new shell
No api_key argument: the constructor finds it in the environment. Note max_completion_tokens — the GPT-5 family rejects the older max_tokens.
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[
{"role": "system", "content": "You are a concise technical assistant."},
{"role": "user", "content": "Explain a database index in two sentences."},
],
max_completion_tokens=500,
)
print(response.choices[0].message.content)
print(response.usage.prompt_tokens, response.usage.completion_tokens)
# OpenAI also offers a newer Responses API (client.responses.create) with
# built-in tools and server-side conversation state. Chat Completions is
# used here because every OpenAI-compatible provider implements it.
The final chunk carries usage and no choices, so guard before indexing. Without stream_options you get no token counts at all from a streamed call.
stream = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[{"role": "user", "content": "Write a haiku about indexes."}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if not chunk.choices: # the usage-only final chunk
continue
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
print()
The model never runs your function — it asks you to. You execute it, append the result keyed by tool_call_id, then call again. Forgetting that second call is the most common mistake here: the model has produced no answer yet.
import json
def get_weather(city: str) -> str:
return json.dumps({"city": city, "celsius": 29, "sky": "clear"})
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city.",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
messages = [{"role": "user", "content": "What is the weather in Delhi?"}]
first = client.chat.completions.create(
model="gpt-5.4-mini", messages=messages, tools=tools,
)
reply = first.choices[0].message
messages.append(reply)
for call in reply.tool_calls or []:
args = json.loads(call.function.arguments) # always parse; never string-match
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": get_weather(**args),
})
second = client.chat.completions.create(
model="gpt-5.4-mini", messages=messages, tools=tools,
)
print(second.choices[0].message.content)
The SDK already retries 429 and 5xx twice with backoff, so catch the ones retrying cannot fix. Treat a length finish_reason as a failure — it is a truncated answer, not a short one.
import openai
try:
response = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[{"role": "user", "content": "..."}],
max_completion_tokens=1000,
)
except openai.AuthenticationError:
raise SystemExit("OPENAI_API_KEY is missing or revoked.")
except openai.NotFoundError:
raise SystemExit("Unknown model id — check the official docs linked below.")
except openai.RateLimitError as e:
# Also raised when the account is out of credit, which no retry fixes.
raise SystemExit(f"Rate limited or out of quota: {e}")
except openai.APIConnectionError:
raise SystemExit("Could not reach the API — check the network or proxy.")
if response.choices[0].finish_reason == "length":
print("Truncated: raise max_completion_tokens or ask for a shorter answer.")
The official OpenAI SDK for Java. Gradle: implementation("com.openai:openai-java:4.69.2").
<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>4.69.2</version>
</dependency>
fromEnv() reads OPENAI_API_KEY. Prefer .model(String) over the ChatModel constants: the typed enum ships with the SDK, so it always lags a new model by a release or two.
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
OpenAIClient client = OpenAIOkHttpClient.fromEnv();
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model("gpt-5.4-mini")
.maxCompletionTokens(500L)
.addSystemMessage("You are a concise technical assistant.")
.addUserMessage("Explain a database index in two sentences.")
.build();
ChatCompletion completion = client.chat().completions().create(params);
completion.choices().get(0).message().content()
.ifPresent(System.out::println);
Close the stream — try-with-resources does it here. It holds an HTTP connection open, and leaking one per request stalls the pool long before you see an error.
import com.openai.core.http.StreamResponse;
import com.openai.models.chat.completions.ChatCompletionChunk;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model("gpt-5.4-mini")
.addUserMessage("Write a haiku about indexes.")
.build();
try (StreamResponse<ChatCompletionChunk> stream =
client.chat().completions().createStreaming(params)) {
stream.stream()
.flatMap(chunk -> chunk.choices().stream())
.flatMap(choice -> choice.delta().content().stream())
.forEach(System.out::print);
}
Keep the params builder around rather than rebuilding it: you append the assistant turn and every tool result to the same builder, then call again. contentAsJson serialises the result for you.
import com.openai.models.FunctionDefinition;
import com.openai.models.FunctionParameters;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
import com.openai.models.chat.completions.ChatCompletionTool;
import com.openai.models.chat.completions.ChatCompletionToolMessageParam;
import java.util.Collection;
import java.util.List;
import java.util.Map;
FunctionParameters schema = FunctionParameters.builder()
.putAdditionalProperty("type", JsonValue.from("object"))
.putAdditionalProperty("properties",
JsonValue.from(Map.of("city", Map.of("type", "string"))))
.putAdditionalProperty("required", JsonValue.from(List.of("city")))
.build();
ChatCompletionTool weatherTool = ChatCompletionTool.builder()
.function(FunctionDefinition.builder()
.name("get_weather")
.description("Current weather for a city.")
.parameters(schema)
.build())
.build();
ChatCompletionCreateParams.Builder conversation =
ChatCompletionCreateParams.builder()
.model("gpt-5.4-mini")
.addTool(weatherTool)
.addUserMessage("What is the weather in Delhi?");
ChatCompletion first = client.chat().completions().create(conversation.build());
first.choices().stream()
.flatMap(choice -> choice.message().toolCalls().stream()
.flatMap(Collection::stream))
.forEach(toolCall -> conversation.addMessage(
ChatCompletionToolMessageParam.builder()
.toolCallId(toolCall.id())
.contentAsJson(Map.of("city", "Delhi", "celsius", 29, "sky", "clear"))
.build()));
ChatCompletion second = client.chat().completions().create(conversation.build());
second.choices().get(0).message().content().ifPresent(System.out::println);
The SDK throws a typed exception per status. Catch the specific ones first — a bare catch hides whether retrying could possibly help.
import com.openai.errors.NotFoundException;
import com.openai.errors.OpenAIIoException;
import com.openai.errors.RateLimitException;
import com.openai.errors.UnauthorizedException;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
try {
ChatCompletion completion = client.chat().completions().create(
ChatCompletionCreateParams.builder()
.model("gpt-5.4-mini")
.maxCompletionTokens(1000L)
.addUserMessage("...")
.build());
completion.choices().get(0).message().content()
.ifPresent(System.out::println);
} catch (UnauthorizedException e) {
System.err.println("OPENAI_API_KEY missing or revoked.");
} catch (NotFoundException e) {
System.err.println("Unknown model id — check the official docs linked below.");
} catch (RateLimitException e) {
System.err.println("Rate limited or out of quota.");
} catch (OpenAIIoException e) {
System.err.println("Could not reach the API — check the network or proxy.");
}
Node 18 or newer. The client reads OPENAI_API_KEY from process.env — never ship a key to the browser, where anyone can read it straight out of the bundle.
npm install openai
export OPENAI_API_KEY="sk-..."
ESM. For CommonJS, const OpenAI = require("openai") instead.
import OpenAI from "openai";
const client = new OpenAI();
const response = await client.chat.completions.create({
model: "gpt-5.4-mini",
messages: [
{ role: "system", content: "You are a concise technical assistant." },
{ role: "user", content: "Explain a database index in two sentences." },
],
max_completion_tokens: 500,
});
console.log(response.choices[0].message.content);
console.log(response.usage.prompt_tokens, response.usage.completion_tokens);
Server-side only. To stream into a browser, proxy it through your own endpoint — putting the key in client-side JavaScript publishes it.
const stream = await client.chat.completions.create({
model: "gpt-5.4-mini",
messages: [{ role: "user", content: "Write a haiku about indexes." }],
stream: true,
stream_options: { include_usage: true },
});
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content;
if (delta) process.stdout.write(delta);
}
Arguments arrive as a JSON string, not an object. Parse it — and validate it, because a model can send a shape your schema did not ask for.
function getWeather({ city }) {
return JSON.stringify({ city, celsius: 29, sky: "clear" });
}
const tools = [{
type: "function",
function: {
name: "get_weather",
description: "Current weather for a city.",
parameters: {
type: "object",
properties: { city: { type: "string" } },
required: ["city"],
},
},
}];
const messages = [{ role: "user", content: "What is the weather in Delhi?" }];
const first = await client.chat.completions.create({
model: "gpt-5.4-mini", messages, tools,
});
const reply = first.choices[0].message;
messages.push(reply);
for (const call of reply.tool_calls ?? []) {
const args = JSON.parse(call.function.arguments);
messages.push({
role: "tool",
tool_call_id: call.id,
content: getWeather(args),
});
}
const second = await client.chat.completions.create({
model: "gpt-5.4-mini", messages, tools,
});
console.log(second.choices[0].message.content);
Use the typed error classes rather than matching on message text, which changes without warning.
import OpenAI from "openai";
try {
const response = await client.chat.completions.create({
model: "gpt-5.4-mini",
messages: [{ role: "user", content: "..." }],
max_completion_tokens: 1000,
});
if (response.choices[0].finish_reason === "length") {
console.warn("Truncated — raise max_completion_tokens.");
}
} catch (error) {
if (error instanceof OpenAI.AuthenticationError) {
console.error("OPENAI_API_KEY missing or revoked.");
} else if (error instanceof OpenAI.NotFoundError) {
console.error("Unknown model id — check the official docs linked below.");
} else if (error instanceof OpenAI.RateLimitError) {
console.error("Rate limited or out of quota.");
} else if (error instanceof OpenAI.APIError) {
console.error(`API error ${error.status}: ${error.message}`);
} else {
throw error;
}
}
QUESTIONS
Which languages are the OpenAI examples in?
C#, Python, Java and JavaScript. Every sample runs as pasted and reads its credentials from an environment variable — no key is ever written into the code.
Which package do I install for OpenAI?
The samples use openai. The install step on each language tab gives the exact command.
Which OpenAI model do these examples use?
gpt-5.4-mini, checked against the official documentation on 25 September 2026. Model ids change often; if a call returns a model-not-found error, check the current list in the official docs.
Where is the official OpenAI documentation?
https://platform.openai.com/docs — it is linked at the bottom of this page, and it is the authority whenever it disagrees with a sample here.
ALSO IN LANGUAGE MODELS
The authority
Official OpenAI documentation
Model names, pricing and rate limits change faster than any page here can. When this page and the official docs disagree, the official docs are right.
https://platform.openai.com/docs