Welcome, and one note before we start
This course is independent. OpenAI has not endorsed it and has no connection to it. Everything here is written from hands-on use and checked against OpenAI's current documentation. The API changes month to month, so when something here differs from the live docs, go with the docs.
By the end of this level you will have three things: a project with its own API key and a spending cap, a script that reads that key without the key ever appearing in your code, and a safety net that stops you from committing the key by mistake. It's dull plumbing, but it prevents a lot of expensive mistakes.
The mental model: organization → project → key
Picture the OpenAI platform as an office building:
- The organization is the company. It owns billing and members.
- A project is one room inside it. Each project has its own keys, usage tracking and spend limits.
- An API key is a door badge. A project key opens one room only.
Project keys begin with sk-proj-. When you create one you pick a permission level:
- All is the default and gives full access.
- Restricted lets you set each endpoint to None, Read or Write.
- Read only can read from every endpoint but can't change anything.
Why bother with a separate project for each app? Because keys leak. They end up in screenshots, in logs, in a teammate's Slack message. A leaked key from your quiz-bot-dev project can only spend quiz-bot-dev money, up to that project's limit, and you revoke it without touching your production app. One shared key does the opposite: the whole organization is exposed, and rotating it breaks everything at once.
Walkthrough 1: create the project, key and limit
- Sign in at
platform.openai.com. Use the project switcher to create a new project, for examplelevelup-course. - With that project selected, open API keys. Create a secret key and set its permissions. For this course, All is fine, but in production choose Restricted and switch on only what the app actually uses.
- Copy the key now. The dashboard won't show the full key again.
- Open the project's Settings → Limits → Spend and set a monthly cap, say $5. Add an alert threshold too.
Gotcha: alert or hard limit? An alert sends you an email, and your requests keep running. A hard limit blocks them: once the project goes over its cap, calls fail with HTTP
429and the codeproject_spend_limit_exceeded. Enforcement isn't instant, so spending can go slightly past the cap. Limits belong to the project, not to an individual key. That's one more reason to give every app its own project.
Walkthrough 2: keep the key out of your code
Both official SDKs look for an environment variable called OPENAI_API_KEY. If it's set, you never need to type the key into your code at all.
The simplest option is a shell variable, which lasts for that session only:
# macOS / Linux
export OPENAI_API_KEY="sk-proj-...your key..."
# Windows PowerShell
$env:OPENAI_API_KEY = "sk-proj-...your key..."
The more comfortable option for a project is a .env file that git ignores. Set up the ignore rule before you create the file:
# 1. Tell git to ignore .env, then commit that rule
echo ".env" >> .gitignore
# 2. Put the real key in .env (never committed)
echo 'OPENAI_API_KEY=sk-proj-...your key...' > .env
# 3. Commit a template with a placeholder so teammates know what's needed
echo 'OPENAI_API_KEY=replace-me' > .env.example
# 4. Check: git should report .env as ignored
git check-ignore -v .env
Walkthrough 3: your first verified call
The example uses gpt-6-luna, the cheapest current general-purpose model, at $0.10 per million input tokens. Choosing models properly is the subject of Level 2.
Python
pip install openai python-dotenv
# first_call.py
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv() # copies .env into os.environ; does nothing if .env is missing
client = OpenAI() # reads OPENAI_API_KEY from the environment by itself
response = client.responses.create(
model="gpt-6-luna",
input="Reply with exactly: key works",
)
print(response.output_text)
JavaScript (Node 20.6+ can read .env files without extra packages)
npm install openai
// first_call.mjs
import OpenAI from "openai";
const client = new OpenAI(); // also reads OPENAI_API_KEY
const response = await client.responses.create({
model: "gpt-6-luna",
input: "Reply with exactly: key works",
});
console.log(response.output_text);
node --env-file=.env first_call.mjs
Check it: the script should print key works or something very close. A 401 error means the key is wrong, revoked or missing. Print len(os.environ.get("OPENAI_API_KEY", "")) to see whether the key was loaded at all; never print the key itself. Next, open the project's usage page: within a few minutes your request should appear under this project, which confirms the key belongs where you think it does. The responses.create call itself is the subject of Level 3.
Walkthrough 4: revoke, rotate and scan
Rotating without downtime goes in this order: create a new key, put it everywhere the old one is used (your .env, your host's secret settings), confirm the app still works, then revoke the old key from the API keys page. Once revoked, the old key fails straight away. Rotate whenever someone leaves the team, a laptop goes missing, or you have any doubt at all.
If a key gets committed, deleting the file in a later commit doesn't help. The key is still in the git history. Revoke it first, then tidy up.
Catch mistakes before they happen with a pre-commit hook. Gitleaks is a popular free choice:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.2 # run `pre-commit autoupdate` to move to the latest version
hooks:
- id: gitleaks
pip install pre-commit
pre-commit install # from now on, gitleaks scans every commit
From now on, a commit containing something that looks like an sk-proj- key is blocked before it's created. As a final backstop, OpenAI is a GitHub secret-scanning partner: when GitHub finds an OpenAI key in a public repository, it reports the key to OpenAI, which disables it automatically. That saves you from the worst outcome, but your app also breaks without warning, so don't rely on it.
Key takeaways
- The structure is organization → project → key. Give each app or environment its own project and key so that a leak can only reach one project's money.
- Set a monthly spend hard limit on every project. Alerts only send email. A hard limit stops requests with a
429 project_spend_limit_exceeded. - Both SDKs read
OPENAI_API_KEYfrom the environment automatically. Keep the key in that variable or in a.envfile that.gitignoreexcludes, and commit only a.env.example. - Rotate in this order: new key, deploy it, verify, revoke the old one. A committed key must be revoked, because git history keeps it.
- Run a pre-commit scanner such as gitleaks. GitHub's partner scanning is the last line of defence, not the first.