Want to add AI capabilities to your application? The ChatGPT API (officially called the OpenAI API) lets you integrate powerful language models into your projects. This complete tutorial covers everything from getting your API key to building production-ready integrations.
Quick Start Overview
| Step | Action | Time |
|---|---|---|
| 1 | Create OpenAI account | 2 min |
| 2 | Get API key | 1 min |
| 3 | Install SDK | 1 min |
| 4 | Make first request | 5 min |
| 5 | Build your app | Varies |
Step 1: Get Your OpenAI API Key
Before using the ChatGPT API, you need an API key:
- Go to platform.openai.com
- Sign up or log in
- Navigate to API Keys in the sidebar
- Click Create new secret key
- Copy and store the key securely (you won't see it again!)
Pricing Note: OpenAI uses pay-as-you-go pricing. GPT-4o costs $2.50/1M input tokens and $10/1M output tokens. GPT-4o-mini is much cheaper at $0.15/1M input and $0.60/1M output.
Step 2: Install the OpenAI SDK
JavaScript/Node.js:
npm install openai
Python:
pip install openai
Step 3: Make Your First API Request
JavaScript Example
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
});
async function chat(message) {
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: message }
]
});
return completion.choices[0].message.content;
}
// Usage
const response = await chat('What is the capital of France?');
console.log(response);
// Output: The capital of France is Paris.
Python Example
from openai import OpenAI
client = OpenAI(api_key='your-api-key')
def chat(message):
completion = client.chat.completions.create(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'You are a helpful assistant.'},
{'role': 'user', 'content': message}
]
)
return completion.choices[0].message.content
# Usage
response = chat('What is the capital of France?')
print(response)
Understanding the Chat Completions API
The ChatGPT API uses a messages array with three role types:
| Role | Purpose | Example |
|---|---|---|
system |
Set AI behavior/personality | "You are a coding assistant" |
user |
User's input/question | "How do I sort an array?" |
assistant |
AI's previous responses | Used for conversation history |
Conversation with History
const conversationHistory = [
{ role: 'system', content: 'You are a helpful coding assistant.' }
];
async function chat(userMessage) {
// Add user message to history
conversationHistory.push({ role: 'user', content: userMessage });
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: conversationHistory
});
const assistantMessage = completion.choices[0].message.content;
// Add assistant response to history
conversationHistory.push({ role: 'assistant', content: assistantMessage });
return assistantMessage;
}
// Multi-turn conversation
await chat('My name is Alex');
await chat('What is my name?'); // AI remembers: "Your name is Alex"
Streaming Responses
For a better user experience, stream responses token by token:
JavaScript Streaming
async function streamChat(message) {
const stream = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: message }
],
stream: true
});
let fullResponse = '';
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
process.stdout.write(content); // Print each token as it arrives
fullResponse += content;
}
console.log(); // New line after streaming
return fullResponse;
}
await streamChat('Write a haiku about programming');
Python Streaming
def stream_chat(message):
stream = client.chat.completions.create(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'You are a helpful assistant.'},
{'role': 'user', 'content': message}
],
stream=True
)
full_response = ''
for chunk in stream:
content = chunk.choices[0].delta.content or ''
print(content, end='', flush=True)
full_response += content
print() # New line
return full_response
stream_chat('Explain quantum computing simply')
Express.js Streaming Endpoint
import express from 'express';
const app = express();
app.use(express.json());
app.post('/api/chat', async (req, res) => {
const { message } = req.body;
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const stream = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: message }
],
stream: true
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
if (content) {
res.write(`data: ${JSON.stringify({ content })}\n\n`);
}
}
res.write('data: [DONE]\n\n');
res.end();
});
app.listen(3000);
Advanced Parameters
Fine-tune the AI's behavior with these parameters:
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{ role: 'user', content: 'Write a creative story' }
],
// Creativity control (0-2, default 1)
temperature: 0.7,
// Alternative to temperature (0-1)
// top_p: 0.9,
// Maximum tokens in response
max_tokens: 1000,
// Stop sequences
stop: ['THE END', '---'],
// Penalize repeated tokens (-2 to 2)
frequency_penalty: 0.5,
// Penalize tokens based on presence (-2 to 2)
presence_penalty: 0.5,
// Generate multiple completions
n: 1,
// Reproducible outputs
seed: 12345
});
Temperature Guide
| Temperature | Use Case | Example |
|---|---|---|
| 0.0 - 0.3 | Factual, deterministic | Code generation, data extraction |
| 0.4 - 0.7 | Balanced | General conversation, summaries |
| 0.8 - 1.2 | Creative | Stories, brainstorming |
| 1.3 - 2.0 | Very random | Experimental, wild ideas |
Function Calling (Tools)
Let ChatGPT call your functions to access external data:
// Define available functions
const tools = [
{
type: 'function',
function: {
name: 'get_weather',
description: 'Get current weather for a location',
parameters: {
type: 'object',
properties: {
location: {
type: 'string',
description: 'City name, e.g., San Francisco, CA'
},
unit: {
type: 'string',
enum: ['celsius', 'fahrenheit'],
description: 'Temperature unit'
}
},
required: ['location']
}
}
}
];
// Your actual function
function getWeather(location, unit = 'celsius') {
// In reality, call a weather API here
return {
location,
temperature: unit === 'celsius' ? 22 : 72,
unit,
condition: 'sunny'
};
}
async function chatWithTools(message) {
const messages = [
{ role: 'user', content: message }
];
// First call - AI decides if it needs to call a function
const response = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages,
tools
});
const assistantMessage = response.choices[0].message;
// Check if AI wants to call a function
if (assistantMessage.tool_calls) {
messages.push(assistantMessage);
// Execute each function call
for (const toolCall of assistantMessage.tool_calls) {
const args = JSON.parse(toolCall.function.arguments);
let result;
if (toolCall.function.name === 'get_weather') {
result = getWeather(args.location, args.unit);
}
// Add function result to messages
messages.push({
role: 'tool',
tool_call_id: toolCall.id,
content: JSON.stringify(result)
});
}
// Second call - AI generates response using function results
const finalResponse = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages
});
return finalResponse.choices[0].message.content;
}
return assistantMessage.content;
}
// Usage
const result = await chatWithTools("What's the weather in Tokyo?");
console.log(result);
// Output: The current weather in Tokyo is sunny with a temperature of 22°C.
JSON Mode (Structured Output)
Force the API to return valid JSON:
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content: 'Extract product information and return as JSON with fields: name, price, category'
},
{
role: 'user',
content: 'The iPhone 15 Pro costs $999 and is a smartphone'
}
],
response_format: { type: 'json_object' }
});
const data = JSON.parse(completion.choices[0].message.content);
console.log(data);
// { "name": "iPhone 15 Pro", "price": 999, "category": "smartphone" }
Structured Outputs (Schema Enforcement)
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{ role: 'user', content: 'Generate 3 fictional users' }
],
response_format: {
type: 'json_schema',
json_schema: {
name: 'users',
schema: {
type: 'object',
properties: {
users: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'integer' },
email: { type: 'string' }
},
required: ['name', 'age', 'email']
}
}
},
required: ['users']
}
}
}
});
Vision (Image Input)
GPT-4o can analyze images:
const completion = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'What is in this image?' },
{
type: 'image_url',
image_url: {
url: 'https://example.com/image.jpg'
}
}
]
}
]
});
console.log(completion.choices[0].message.content);
Base64 Image
import fs from 'fs';
const imageBuffer = fs.readFileSync('local-image.jpg');
const base64Image = imageBuffer.toString('base64');
const completion = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Describe this image in detail' },
{
type: 'image_url',
image_url: {
url: `data:image/jpeg;base64,${base64Image}`
}
}
]
}
]
});
Error Handling
Handle common API errors gracefully:
import OpenAI from 'openai';
const openai = new OpenAI();
async function safeChatCompletion(messages, retries = 3) {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages
});
return completion.choices[0].message.content;
} catch (error) {
if (error instanceof OpenAI.APIError) {
console.error(`Attempt ${attempt} failed:`, error.message);
// Rate limit - wait and retry
if (error.status === 429) {
const waitTime = Math.pow(2, attempt) * 1000;
console.log(`Rate limited. Waiting ${waitTime}ms...`);
await new Promise(r => setTimeout(r, waitTime));
continue;
}
// Authentication error - don't retry
if (error.status === 401) {
throw new Error('Invalid API key');
}
// Server error - retry
if (error.status >= 500) {
continue;
}
}
throw error;
}
}
throw new Error('Max retries exceeded');
}
Cost Optimization Tips
1. Use the Right Model
// For simple tasks, use gpt-4o-mini (10x cheaper)
const simpleResponse = await openai.chat.completions.create({
model: 'gpt-4o-mini', // $0.15/1M input, $0.60/1M output
messages: [{ role: 'user', content: 'Translate "hello" to Spanish' }]
});
// For complex reasoning, use gpt-4o
const complexResponse = await openai.chat.completions.create({
model: 'gpt-4o', // $2.50/1M input, $10/1M output
messages: [{ role: 'user', content: 'Analyze this legal document...' }]
});
2. Limit Token Usage
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: 'Summarize in 2 sentences' }],
max_tokens: 100 // Limit response length
});
3. Cache Responses
import NodeCache from 'node-cache';
const cache = new NodeCache({ stdTTL: 3600 }); // 1 hour cache
async function cachedChat(message) {
const cacheKey = `chat:${message}`;
// Check cache first
const cached = cache.get(cacheKey);
if (cached) {
return cached;
}
// Make API call
const response = await chat(message);
// Cache the response
cache.set(cacheKey, response);
return response;
}
Building a Simple Chatbot
Complete example of a CLI chatbot:
import OpenAI from 'openai';
import readline from 'readline';
const openai = new OpenAI();
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const conversationHistory = [
{
role: 'system',
content: `You are a helpful assistant. Be concise but friendly.
If you don't know something, say so.`
}
];
async function chat(userMessage) {
conversationHistory.push({ role: 'user', content: userMessage });
try {
const stream = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: conversationHistory,
stream: true
});
process.stdout.write('Assistant: ');
let fullResponse = '';
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
process.stdout.write(content);
fullResponse += content;
}
console.log('\n');
conversationHistory.push({ role: 'assistant', content: fullResponse });
} catch (error) {
console.error('Error:', error.message);
}
}
function prompt() {
rl.question('You: ', async (input) => {
const trimmed = input.trim();
if (trimmed.toLowerCase() === 'exit') {
console.log('Goodbye!');
rl.close();
return;
}
if (trimmed) {
await chat(trimmed);
}
prompt();
});
}
console.log('ChatGPT CLI (type "exit" to quit)\n');
prompt();
Conclusion
The ChatGPT API is powerful and flexible. Start with gpt-4o-mini for cost-effective development, then upgrade to gpt-4o for complex tasks. Key takeaways:
- Use streaming for better UX
- Implement function calling for dynamic data
- Handle errors gracefully with retries
- Cache responses to reduce costs
Related Resources: