How to Get an OpenAI API Key (ChatGPT API)
9 min read · 1,767 wordsBogdan KolomietsBogdan Kolomiets

How to Get an OpenAI API Key (ChatGPT API)

TL;DR

Create an OpenAI API key step by step: project vs user keys, billing tiers, curl and Python calls, safe storage, and spend limits.

Creating the key takes about a minute. Everything around it — which account it belongs to, which project it bills to, what it may do, and where you store it — is what people actually get wrong.

I have set up these credentials for dozens of generation pipelines, my own and other people's, and the pattern repeats: the key itself is rarely the problem, the account structure behind it is. Here is the whole path, from the account to the first successful call, with the traps marked as they come.

A ChatGPT subscription is not API access

This is the most common misunderstanding, so it goes first.

A ChatGPT Plus, Pro or Team subscription pays for the chat interface — the web and mobile apps. The API is a separate product with its own balance, billed by tokens rather than by month. One account can hold both, but the money does not move between them: there is no mechanism to convert an unused subscription into API credits.

| | Chat subscription | API access | | --- | --- | --- | | Where it works | chatgpt.com and the apps | your own code, bots, third-party tools | | How you pay | fixed monthly fee | prepaid credits, charged per token | | What limits you | message caps and model availability | credit balance and rate limits |

So if you subscribed and then got an authentication error from your script, nothing is broken. You have not set up API billing yet.

What you need before you create a key

Four things, in this order.

**An account.** The same login you use for ChatGPT works. Sign in at the developer dashboard rather than the chat app — they are different surfaces of the same account.

**An organization.** Keys are issued inside an organization, not floating in your account. If you have never opened the developer dashboard, you will be asked to create one on first sign-in. Requests made without an organization are rejected at authentication.

**A project.** Projects are the unit that matters day to day: rate limits, spend limits and keys are all scoped to one. Even solo, split production from experiments — it costs nothing and makes both spend tracking and incident response trivial.

**Billing.** API usage is prepaid. OpenAI runs a tiered system where your limits grow with cumulative spend: there is a free tier available in supported geographies, and Tier 1 unlocks once $5 has been paid, with higher tiers at $50, $100, $250 and $1,000. Those thresholds govern approved usage limits, not a gift balance — check the billing page in your own dashboard for what applies today. API access is not offered in every country, and requests from unsupported locations are refused regardless of the key.

Creating the key, step by step

The dashboard changes its layout more often than the documentation does, so navigate by name, not by memorised clicks.

1. **Open the API keys page.** It lives at `platform.openai.com/api-keys`, and is also reachable through organization settings. The page lists what already exists: name, creation date, last used date. Full key values are never shown here — only a truncated tail. 2. **Create a new secret key.** Give it a name that says where it will run ("wordpress-prod", not "test2"). Six months later, unnamed keys are indistinguishable and nobody dares delete any of them. 3. **Attach it to a project.** A key created inside a project inherits that project's limits and reports its spend there. This is the step people skip, and it is the one that later makes "who spent this?" unanswerable. 4. **Set permissions.** A key does not have to be all-powerful. You can scope what it may call, which lets you issue, for example, a read-only credential for a dashboard that watches usage but must never be able to spend anything. 5. **Copy it once.** The secret is displayed exactly once. Close the dialog and it is gone — there is no recovery flow, only issuing a replacement.

Keys are prefixed so you can tell them apart at a glance: project-scoped keys start with `sk-proj-`. Admin credentials for the administration endpoints are a separate type issued on their own page — do not use one for model requests.

Project keys, user keys, and service accounts

A key created by a person is tied to that person's access. Permissions are evaluated as the intersection of two things: what the key is allowed to do, and what role its owner still holds in the project. When someone leaves the team and their roles are removed, credentials they created stop working — even though the string is intact and nobody revoked it. Outages traced to "the key just stopped" often turn out to be an offboarding.

For anything that runs unattended, the right answer is a **service account**: a project-level identity that exists independently of any human. It survives staff changes and keeps ownership of the credential with the project rather than with an employee.

Older user-level keys still work but are treated as legacy. If you belong to several organizations, or you are still on such a key, be explicit about routing:

curl https://api.openai.com/v1/models \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Organization: $ORGANIZATION_ID" \
  -H "OpenAI-Project: $PROJECT_ID"

Worth knowing about timing: revoking a key takes effect within seconds, but other changes affecting what a key may do can take up to about fifteen minutes to propagate. If you just adjusted permissions and behaviour has not changed, wait before assuming it failed.

Making your first call

Export the key as an environment variable rather than pasting it into code. The official SDKs read `OPENAI_API_KEY` from the environment automatically, which keeps your source shareable.

export OPENAI_API_KEY="your_key_here"       # macOS / Linux
setx OPENAI_API_KEY "your_key_here"         # Windows

The fastest proof that the credential is alive involves no model at all:

curl https://api.openai.com/v1/models \
  -H "Authorization: Bearer $OPENAI_API_KEY"

A list of models means the key, organization and billing are all fine, and any remaining bug is in your application. Then a real request — Python first:

from openai import OpenAI

client = OpenAI()

response = client.responses.create(
    model="gpt-5.6",
    input="Write a one-sentence bedtime story about a unicorn.",
)

print(response.output_text)

And the JavaScript equivalent:

import OpenAI from "openai";
const client = new OpenAI();

const response = await client.responses.create({
  model: "gpt-5.6",
  input: "Write a one-sentence bedtime story about a unicorn.",
});

console.log(response.output_text);

Model names move faster than any article can. Take the identifier from the models page in the documentation at the moment you write the code, and keep it in configuration rather than hard-coded in five places.

If that first call comes back `401`, do not regenerate the key reflexively. The usual causes are a truncated paste, an invisible trailing space, a process that never restarted after rotation, or a request routed to the wrong project — I have written that diagnosis up separately in [fixing the invalid API key error](https://ai-seowriter.ru/en/blog/invalid-api-key-openai), including how `401` differs from `403` and `429`. If you are still comparing providers, [creating an OpenRouter key](https://ai-seowriter.ru/en/blog/openrouter-api-key) follows a similar shape with a different billing model behind it.

Storing the key so it does not leak

A leaked credential is not an abstract security problem. It is someone else's traffic on your balance.

Never ship a key to the browser or a mobile app. Anything client-side is readable no matter how it is obfuscated, so route model calls through your own backend. Never commit it either — public repositories are scanned continuously, and because history is searchable, deleting the line in a later commit does not help. If it was ever pushed, rotate it.

Beyond that: environment variables locally and a secrets manager in production, a separate key per integration so revoking one does not take down the rest, and no keys sent through chat apps. Every team member should have their own; sharing one makes spend impossible to attribute and forces a full rotation the moment any single laptop is compromised.

Rotation order matters, and getting it backwards causes the outage you were trying to avoid: create the replacement, deploy it, confirm traffic is flowing, then revoke the old one.

Two more controls. The keys page shows a last-used date, which makes quarterly cleanup mechanical. And organizations can enable IP allowlisting, so requests from outside your infrastructure are rejected even when they carry a valid key.

Keeping spend under control

Two separate mechanisms here, and people routinely configure the wrong one.

A **spend alert** notifies you at a threshold and lets traffic continue. A **hard spend limit** actually stops requests once tracked spend reaches the configured amount. Both can be set for the whole organization and for individual projects, in the limits section of the respective settings.

When a limit bites, the API returns `429` with a code naming the wall you hit: `organization_spend_limit_exceeded`, `project_spend_limit_exceeded`, or `credit_balance_exhausted` when prepaid credits simply ran out. That last one is not a rate-limiting problem, and no amount of retrying will clear it.

Ordinary rate limits also return `429`, which is why reading `error.code` matters more than reading the status number. Responses carry `x-ratelimit-*` headers showing what remains and when it resets, plus a `Retry-After` header on temporary rate limits — honour it instead of retrying blindly.

My default on a new project: a hard limit slightly above expected monthly usage, plus an alert at half of it. A runaway background job then gets capped by policy rather than discovered on an invoice.

When you do not need a key at all

Managing credentials is worth it when you are building a product on the model. If the goal is simply publishing content, the key is an extra moving part between you and the result: our [SEO article generator](https://ai-seowriter.ru/en/generator-seo-statej) runs on the service's own keys and publishes straight to your CMS, and you can connect your own provider keys later if you would rather control that billing yourself.

Frequently asked questions

**Does my ChatGPT subscription include API calls?** No. Separate products, separate balances, no conversion between them.

**Do keys expire?** No. A key works until it is revoked, which is exactly why forgotten ones are dangerous.

**How many keys can I create?** Enough that you should be generous with them — one per integration and per environment is the sane default.

**Can the team share one key?** Technically yes, practically no. Spend becomes unattributable, and a single leak forces you to break every integration at once.

**Is a "ChatGPT API key" the same as an "OpenAI API key"?** Yes. The documentation uses the second term; both name the same credential.

Automate SEO publishing with SEO Writer

AI writes articles, publishes to CMS, fills meta tags — without your involvement

Start for free →