You know that task you do every morning? The one that takes 10–15 minutes and involves the same basic steps, but with slightly different details each time?
That is exactly what the OpenAI API was built to handle.
Most people think automation only works for identical, scripted tasks. But modern AI can handle variation, the kind of work where the process is the same, but the content changes.
Getting Started: Your First API Call
from openai import OpenAI # Create the OpenAI client # It automatically reads OPENAI_API_KEY from environment variables client = OpenAI() # Make an API call to generate text using the Responses API response = client.responses.create( model="gpt-4o-mini", # The AI model to use input="Write a professional email declining a meeting request." ) # Print the generated response print(response.output_text)
This sends your prompt to OpenAI and returns the result. That is the foundation. Everything else builds from here.
Note: This uses the Responses API, which OpenAI now recommends for all new projects. It is simpler than the older Chat Completions API and offers better performance, lower costs, and built-in support for tools like web search. Always check the Models page for the latest available models.
Why Responses API?
The Responses API is OpenAI's evolution of their Chat Completions API. Here is why it matters for your automations:
- Simpler syntax: Use
inputinstead of constructing message arrays, and get results withoutput_textinstead of navigating nested objects. Less code to write, fewer places for bugs to hide. - Better performance: The AI gives you smarter, more accurate answers, which is especially helpful when you are building automations that need to think through problems or write code.
- Lower costs (often): Features like response caching or Flex processing can reduce costs for repeated or asynchronous workloads. Always verify against current pricing for your specific use case.
- Built-in tools (model-dependent): Support for web search, file search, image generation, and code interpreter via the Responses API tools. Availability depends on which model you use.
- Future-proof: All new OpenAI features will launch on the Responses API first, so you will not need to rewrite your code later.
If you see older tutorials using chat.completions.create(), they still work, but responses.create() is the modern approach.
Keep Your API Key Safe: Use Environment Variables
Never hardcode your API key in your scripts. If you accidentally commit it to GitHub or share your code, someone could use your key and rack up charges on your account.
Instead, store it in a .env file:
Step 1: Create a file named .env in your project directory:
OPENAI_API_KEY=sk-proj-your-actual-api-key-here
Step 2: Install python-dotenv:
pip install python-dotenv
Step 3: Load your key from the environment:
from openai import OpenAI from dotenv import load_dotenv # Load environment variables from .env file into the system environment load_dotenv() # Create OpenAI client - it automatically reads OPENAI_API_KEY from environment client = OpenAI() # Make the API call using the Responses API response = client.responses.create( model="gpt-4o-mini", input="Write a professional email declining a meeting request." ) # Print the result print(response.output_text)
Step 4: Add .env to your .gitignore file:
.env
This ensures your API key never gets committed to version control. Your code stays shareable, and your key stays private.
The Anatomy of a Good Automation Prompt
from openai import OpenAI client = OpenAI() # Define a reusable prompt template with a placeholder for the sender name prompt = '''You are a professional email writer. Draft a polite decline for a meeting request from {sender_name}, a potential vendor. Context: - We are not currently accepting new vendor proposals - Keep the tone friendly but firm - Suggest they check back in Q2 next year Format: Return only the email body, no subject line. Length: Under 100 words.''' # Fill in the placeholder with actual data filled_prompt = prompt.format(sender_name="John from Acme Corp") # Make the API call with the customized prompt response = client.responses.create( model="gpt-4o-mini", input=filled_prompt ) # Print the generated email print(response.output_text)
The more specific you are, the more consistent your results.
Error Handling and Reliability
When you are automating tasks, things will go wrong. The API might be slow, your internet might hiccup, or you might hit rate limits. Your script needs to handle these gracefully.
Why retry with exponential backoff?
If the API fails, you do not want to retry immediately. That is like knocking on a door, getting no answer, then immediately knocking again. Instead:
- First retry: Wait 1 second
- Second retry: Wait 2 seconds
- Third retry: Wait 4 seconds
Each retry waits longer, giving the system time to recover.
What is jitter and why do we need it?
Jitter means adding a small random delay (like 0.1–0.5 seconds). Here is why it matters:
Imagine the OpenAI API goes down at 2:00 PM. Without jitter:
- 1,000 people's scripts all fail at the exact same moment
- They all schedule their retry for exactly 2:01 PM
- At 2:01 PM, 1,000 requests hit the server simultaneously
- The server gets overwhelmed again (this is called a thundering herd)
With jitter:
- Those 1,000 retries spread out: 2:01:00.1, 2:01:00.3, 2:01:00.7, etc.
- The server can handle the gradual flow of requests
- Your automation is more likely to succeed
Now here is how to implement it:
import time
import random
from openai import OpenAI
from openai import (
APITimeoutError,
APIConnectionError,
RateLimitError,
APIStatusError,
)
client = OpenAI()
def call_openai_with_retry(prompt, max_retries=3, model="gpt-4o-mini", timeout=30):
"""
Call OpenAI API with automatic retry logic for transient failures.
Args:
prompt: The prompt to send to the API
max_retries: Maximum number of retry attempts (default: 3)
model: Model to use (default: "gpt-4o-mini")
timeout: Request timeout in seconds (default: 30)
Returns:
The generated text response from the API
"""
for attempt in range(max_retries):
try:
# Make the API call using the Responses API
response = client.responses.create(
model=model,
input=prompt,
timeout=timeout,
)
return response.output_text
except (APITimeoutError, APIConnectionError) as e:
# Network issues or timeouts - these are transient, so retry
if attempt < max_retries - 1:
# Wait 1s, 2s, 4s, etc. + random 0-0.5s (exponential backoff with jitter)
sleep_time = (2 ** attempt) + random.uniform(0, 0.5)
print(f"Connection issue. Retrying in {sleep_time:.1f}s...")
time.sleep(sleep_time)
continue
# If we've exhausted retries, raise the exception
raise
except RateLimitError as e:
# Hit rate limits - respect Retry-After header if present
if attempt < max_retries - 1:
# Check if API provided a retry-after time
retry_after = getattr(e, "retry_after", None)
if retry_after:
print(f"Rate limited. Retrying after {retry_after}s...")
time.sleep(retry_after)
else:
# No retry-after header, use exponential backoff
sleep_time = (2 ** attempt) + random.uniform(0, 0.5)
print(f"Rate limited. Retrying in {sleep_time:.1f}s...")
time.sleep(sleep_time)
continue
raise
except APIStatusError as e:
# HTTP errors - 5xx are server errors (transient), 4xx are client errors (not transient)
status_code = getattr(e, "status_code", 500)
if status_code >= 500 and attempt < max_retries - 1:
# Server error - retry with backoff
sleep_time = (2 ** attempt) + random.uniform(0, 0.5)
print(f"Server error {status_code}. Retrying in {sleep_time:.1f}s...")
time.sleep(sleep_time)
continue
# Client error (4xx) or exhausted retries - raise
raise
# Example usage
try:
result = call_openai_with_retry("Write a professional email declining a meeting request.")
print(result)
except Exception as e:
print(f"Failed after retries: {e}")
This handles the most common API issues: timeouts, connection failures, rate limits, and server errors. The exponential backoff with jitter prevents overwhelming the API when it comes back online.
Stay Current: Check the Documentation Regularly
The AI industry moves incredibly fast. Features that did not exist last month might solve your current problem today. Bugs you are struggling with might have been fixed in the latest release.
Make it a habit to check the OpenAI API documentation and Anthropic documentation on a weekly or monthly basis.
You will discover:
- New models with better capabilities or lower costs
- Updated features that could improve your automations
- Deprecation notices for methods you might be using
- Best practices that have evolved since you first learned
- Bug fixes for issues you thought were your fault
The documentation is not just for beginners. It is your competitive advantage in an industry where things change constantly.
Bookmark these:
- OpenAI Platform Documentation
- Anthropic Claude Documentation
- OpenAI API Reference
- Anthropic API Reference
Final Thought
The best automations are not the most complex. They are the ones that save you from doing the same thing over and over.
If you find yourself copying, pasting, and tweaking the same work every day, that is your signal.
Build a simple script. Add an OpenAI API call. Test it. Improve it.
That is vibecoding. Automate the repetitive. Focus on what actually matters.
