How to Use OpenAI API in R

llm
openai
Learn to use ChatGPT and OpenAI’s API in R. Connect to GPT-4, generate text, create chat completions, and build AI-powered R applications.
Published

April 4, 2026

Introduction

OpenAI’s API gives you access to powerful language models like GPT-4 and GPT-4o directly from R. You can generate text, answer questions, analyze data, and build AI-powered applications.

Alternatives: If you prefer Claude or want to run models locally with Ollama, the ellmer package provides a unified interface for all providers.

What you’ll learn: - Set up OpenAI API access - Use the openai R package - Create chat completions - Handle responses and errors - Manage costs with token limits

Getting Started

Install the openai package

install.packages("openai")
library(openai)

Get your API key

  1. Create an account at platform.openai.com
  2. Go to API Keys section
  3. Create a new secret key
  4. Add billing information (API access requires payment)

Set your API key

# Option 1: Set for current session
Sys.setenv(OPENAI_API_KEY = "sk-your-key-here")

# Option 2: Add to .Renviron (recommended)
usethis::edit_r_environ()
# Add: OPENAI_API_KEY=sk-your-key-here

Create Chat Completions

The main function for interacting with ChatGPT:

library(openai)

response <- create_chat_completion(
  model = "gpt-5.4-mini",
  messages = list(
    list(role = "user", content = "What is R programming?")
  )
)

# Extract the response text
response$choices[[1]]$message$content

With system prompt

Control the assistant’s behavior:

response <- create_chat_completion(
  model = "gpt-5.4-mini",
  messages = list(
    list(role = "system", content = "You are a helpful R programming tutor."),
    list(role = "user", content = "Explain what a data frame is.")
  )
)

Multi-turn conversation

messages <- list(
  list(role = "system", content = "You are an R expert."),
  list(role = "user", content = "How do I read a CSV file?"),
  list(role = "assistant", content = "Use read.csv() or readr::read_csv()..."),
  list(role = "user", content = "What's the difference between them?")
)

response <- create_chat_completion(
  model = "gpt-5.4-mini",
  messages = messages
)

Available Models

GPT-5 Series (Latest)

Model Best For Cost
gpt-5.4 Complex reasoning, coding Higher
gpt-5.4-mini Fast, everyday tasks Medium
gpt-5.4-nano Lowest latency, budget Lower

O-Series (Reasoning Models)

Model Best For Cost
o3 Most powerful reasoning Highest
o3-mini Balanced reasoning Medium
o4-mini Affordable reasoning Lower

Legacy Models (still available in API)

Model Notes
gpt-4o Retired from ChatGPT Feb 2026, API still available
gpt-4-turbo 128k context
# List available models
models <- list_models()

Control Response Parameters

Temperature (creativity)

# More deterministic (good for code)
create_chat_completion(
  model = "gpt-5.4-mini",
  messages = list(list(role = "user", content = "Write R code to calculate mean")),
  temperature = 0.2
)

# More creative (good for brainstorming)
create_chat_completion(
  model = "gpt-5.4-mini",
  messages = list(list(role = "user", content = "Suggest project ideas")),
  temperature = 0.9
)

Limit response length

response <- create_chat_completion(
  model = "gpt-5.4-mini",
  messages = list(list(role = "user", content = "Explain ggplot2")),
  max_tokens = 150  # Limit response length
)

Practical Examples

Generate R code

Use a system prompt to get code-only responses:

prompt <- "Write R code to:
1. Load the mtcars dataset
2. Calculate average mpg by cylinder count
3. Create a bar chart of the results"

Set low temperature for deterministic code:

response <- create_chat_completion(
  model = "gpt-5.4",
  messages = list(
    list(role = "system", content = "Return only R code, no explanations."),
    list(role = "user", content = prompt)
  ),
  temperature = 0.2
)

cat(response$choices[[1]]$message$content)

Analyze text data

Create a reusable sentiment classifier. For more robust extraction, see How to Extract Structured Data with LLMs.

analyze_sentiment <- function(text) {
  response <- create_chat_completion(
    model = "gpt-5.4-mini",
    messages = list(
      list(role = "system", content = "Classify as positive/negative/neutral. One word only."),
      list(role = "user", content = text)
    ),
    temperature = 0
  )
  response$choices[[1]]$message$content
}

Apply to multiple reviews:

reviews <- c("Great product!", "Terrible quality", "It's okay")
sapply(reviews, analyze_sentiment)
# "positive", "negative", "neutral"

Summarize text

long_text <- "Your long document here..."

response <- create_chat_completion(
  model = "gpt-5.4-mini",
  messages = list(
    list(role = "system", content = "Summarize the following text in 2-3 sentences."),
    list(role = "user", content = long_text)
  )
)

Using httr2 Directly

For more control, call the API directly with httr2.

Build the request

library(httr2)

response <- request("https://api.openai.com/v1/chat/completions") |>
  req_headers(
    Authorization = paste("Bearer", Sys.getenv("OPENAI_API_KEY")),
    `Content-Type` = "application/json"
  ) |>
  req_body_json(list(
    model = "gpt-5.4-mini",
    messages = list(list(role = "user", content = "Hello!"))
  )) |>
  req_perform() |>
  resp_body_json()

Extract the response

response$choices[[1]]$message$content

Error Handling

safe_completion <- function(prompt) {
  tryCatch({
    response <- create_chat_completion(
      model = "gpt-5.4-mini",
      messages = list(list(role = "user", content = prompt))
    )
    response$choices[[1]]$message$content
  }, error = function(e) {
    message("API Error: ", e$message)
    NA
  })
}

# Use safely
result <- safe_completion("What is 2+2?")

Common errors

Error Cause Solution
401 Unauthorized Invalid API key Check OPENAI_API_KEY
429 Rate limit Too many requests Add delays between calls
400 Bad request Invalid parameters Check model name, messages format

Cost Management

Understand tokens

# Rough estimate: 1 token ≈ 4 characters in English
# "Hello, how are you?" ≈ 6 tokens

# Check usage in response
response <- create_chat_completion(
  model = "gpt-5.4-mini",
  messages = list(list(role = "user", content = "Hi"))
)

response$usage
# $prompt_tokens: 9
# $completion_tokens: 10
# $total_tokens: 19

Limit costs

# Use cheaper models for simple tasks
create_chat_completion(
  model = "gpt-5.4-mini",  # Cheaper than gpt-4o
  messages = list(list(role = "user", content = prompt)),
  max_tokens = 100  # Limit response length
)

Batch Processing

Process multiple items efficiently:

library(purrr)

texts <- c("Text 1", "Text 2", "Text 3")

# Add delay to avoid rate limits
results <- map(texts, \(text) {
  Sys.sleep(0.5)  # 500ms delay

  response <- create_chat_completion(
    model = "gpt-5.4-mini",
    messages = list(
      list(role = "user", content = paste("Summarize:", text))
    )
  )
  response$choices[[1]]$message$content
})

Alternative: ellmer Package

The tidyverse-friendly alternative:

install.packages("ellmer")
library(ellmer)

chat <- chat_openai(model = "gpt-5.4-mini")
chat$chat("What is R programming?")

See our ellmer tutorial for more details.

Common Mistakes

1. Forgetting to set API key

# Check if key is set
Sys.getenv("OPENAI_API_KEY")
# Should not be empty

2. Not handling rate limits

# Add delays in loops
for (item in items) {
  result <- create_chat_completion(...)
  Sys.sleep(1)  # Wait 1 second
}

3. Using expensive models for simple tasks

# gpt-5.4-mini is often sufficient and much cheaper
# Only use gpt-5.4 or o3 for complex reasoning tasks

4. Not checking response structure

# Always verify the response has expected content
if (!is.null(response$choices[[1]]$message$content)) {
  result <- response$choices[[1]]$message$content
}

Summary

Task Code
Basic completion create_chat_completion(model, messages)
Set API key Sys.setenv(OPENAI_API_KEY = "key")
Control creativity temperature = 0.2 (low) to 0.9 (high)
Limit response max_tokens = 100
Check usage response$usage$total_tokens
  • Start with gpt-5.4-mini for cost efficiency
  • Use o3 or o3-mini for complex reasoning tasks
  • Use low temperature for deterministic outputs
  • Add delays when processing multiple items
  • Always handle errors gracefully

Sources