GPT actions: letting ChatGPT call your apis
GPT Actions let a custom GPT call external APIs you describe, so instead of guessing, ChatGPT fetches live data or triggers a real system on your behalf. You write a small OpenAPI spec, point it at your endpoint, set up auth, and the model decides when to call it during a conversation.
This is the same machinery as function calling in the APIAPIApplication Programming Interface: a standardised interface that lets applications communicate and exchange data without knowing each other's internal workings.View full definition →, but packaged for the no-code Custom GPT builder. **You define the *tools*, ChatGPT handles the *when* and *how***.
What an Action actually is
An Action is one or more HTTP endpoints exposed to a GPT through an [OpenAPI specification](https://platform.openai.com/docs/actions/introduction). OpenAPI (formerly Swagger) is a standard, machine-readable description of a REST API: its paths, parameters, request bodies, and responses.
When you add an Action to a GPT, three things happen at runtime:
- The model reads your operation descriptions and decides a call is needed.
- ChatGPT constructs the HTTP request (filling in parameters from the conversation), attaches auth, and sends it.
- Your API responds with JSON, and the model reads that JSON to write its answer.
The model never sees your server. It only sees the schemaschemaA schema is the formal blueprint that defines how data is structured, named, typed, and related within a database, file, or message.View full definition → you gave it and the response that comes back. That means **your description fields are not documentation, they are *prompt*. Vague descriptions produce wrong calls**.
Where Actions live
Actions are configured inside the GPT editor at chatgpt.com (Explore GPTs, Create, then the Configure tab). Scroll to Actions and click Create new action. You paste a schema, choose an authentication type, and ChatGPT validates it on the spot.
Do not confuse Actions with Connectors. Connectors are prebuilt, OpenAI-managed integrations (Google Drive, SharePoint, GitHub, and others) that bring data *into* ChatGPT for search and retrieval. Actions are *your* custom API calls, defined by you. Use a Connector when one exists for the source; build an Action when you need to hit your own backend or trigger something.
A concrete example: order status lookup
Say your support team wants a GPT that answers "Where is order 10428?" by calling your internal orders API. Your endpoint already exists:
GET https://api.acme-shop.com/v1/orders/{orderId}It returns something like:
{
"orderId": "10428",
"status": "shipped",
"carrier": "DHL",
"trackingNumber": "JD0149...",
"estimatedDelivery": "2026-02-14"
}Now you describe that endpoint to the GPT. Here is a clean, minimal OpenAPI 3.1 schema you can paste directly into the Actions editor:
openapi: 3.1.0
info:
title: Acme Orders API
version: 1.0.0
servers:
- url: https://api.acme-shop.com/v1
paths:
/orders/{orderId}:
get:
operationId: getOrderStatus
summary: Get the current status and tracking info for one order.
description: >
Look up a single order by its numeric ID. Use this whenever a
user asks where their order is, its delivery date, or its
shipping status. Returns status, carrier, and tracking number.
parameters:
- name: orderId
in: path
required: true
description: The order's numeric ID, e.g. 10428.
schema:
type: string
responses:
"200":
description: Order found.
content:
application/json:
schema:
type: object
properties:
orderId: { type: string }
status: { type: string }
carrier: { type: string }
trackingNumber: { type: string }
estimatedDelivery: { type: string, format: date }
"404":
description: No order with that ID exists.A few things make this schema good rather than just valid:
- `operationId` is descriptive.
getOrderStatusreads better to the model thanget1. This becomes the function name. - The `description` tells the model when to use it. Note the "Use this whenever a user asks..." sentence. That is intent routing.
- The `404` is documented. When the model gets a 404, it can tell the user "I couldn't find that order" instead of hallucinating a status.
Once saved, ChatGPT shows the available operation. Test it by asking the GPT a natural question. The first time it calls a new domain, ChatGPT prompts the user to confirm, then sends the request.
Authentication
Actions support three auth modes in the builder: None, API Key, and OAuth. The schema above declares *what* to call; auth controls *how you prove who you are*.
API Key
The simplest secured option. You paste a key into the GPT editor, choose how it is sent (Bearer header, Basic, or a custom header), and OpenAI stores it encrypted. ChatGPT attaches it to every call. Add a matching securitySchemes block to your schema:
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
security:
- bearerAuth: []The key is shared by everyone who uses the GPT. That is fine for a read-only internal endpoint behind your own network controls. It is *not* fine when each user should see only their own dataown dataData collected directly from your own customers and prospects through your own channels: your most reliable and privacy-compliant source.View full definition →, because the model would act with one shared identity.
OAuth
When you need per-user identity (each support agent, or each customer, authenticating as themselves), use OAuth. You provide the authorization URL, tokentokenA token is the basic unit of text that language models process, often a word fragment, whole word, or punctuation mark rather than a single character.View full definition → URL, client ID, client secret, and scopes. ChatGPT runs the standard OAuth flow: the user clicks Sign in, approves access on your auth server, and ChatGPT stores that user's token. Calls then carry *that user's* permissions.
This is the right choice for anything that writes data or exposes private records. Full setup is in the Actions authentication docs.
Build a Custom GPT with Actions
A note on secrets and rate limits
Never put credentials in the schema itself or in the GPT's instructions. Anyone who can use a GPT can sometimes coax it into revealing its configuration. Keep secrets in the dedicated auth fields, and protect your endpoint with its own rate limiting. A popular GPT can generate real traffic, and the model may retry on errors.
Designing the API for a model, not a human
A REST API built for engineers and one built for an LLMLLMA Large Language Model is an AI system trained on vast text data to predict and generate language, enabling tasks like writing, summarizing, and answering questions.View full definition → differ in subtle ways. Tighten these:
- Return small, flat JSON. The response goes into the context windowcontext windowThe context window is the maximum amount of text (measured in tokens) a language model can process at once, including both the input prompt and the generated output.View full definition → and costs tokens. Strip fields the model does not need. An order lookup does not need the full audit log.
- Use clear field names.
estimatedDeliverybeatsest_dlv_dt. The model reasons over names. - Make errors legible. Return a human-readable
messageon failures so the model can relay it. - Keep operations narrow. One endpoint that does five things confuses routing. Prefer
getOrderStatus,cancelOrder, andgetInvoiceas separate operations with separate descriptions.
A consequence worth internalizing: **the model can only do what your schema *describes***. If you want it to cancel orders, you need a cancelOrder operation (a POST or DELETE) with its own description and, ideally, OAuth so the action runs as a real user with permission to cancel.
Knowledge check
1. What is the primary purpose of a GPT Action?
2. Why does the lesson stress that your OpenAPI 'description' fields are 'prompt, not documentation'?
3. In a scenario where you need to bring data from Google Drive into ChatGPT for search and retrieval, what should you use?
4. Select ALL statements that correctly describe what happens at runtime when a GPT uses an Action.
Select all the correct answers.
5. Select ALL correct statements distinguishing Actions from Connectors.
Select all the correct answers.
Consequential actions and confirmation
Some calls are read-only. Some change the world: refund a payment, send an email, delete a record. ChatGPT treats these differently.
By default, ChatGPT asks the user to confirm before calling an Action on a new domain. For writes, you want that friction. You can mark operations so the user must confirm each time, which is good practice for anything destructive. Treat every `POST`, `PUT`, `PATCH`, and `DELETE` as consequential until proven otherwise, and design your endpoint so a confirmation step is cheap (for example, a two-call flow: one to preview, one to commit).
Keep a clear boundary in mind. The GPT is reasoning over your descriptions and may call the wrong operation or pass the wrong argument. **Your *server* is the real authority**. Validate every request server-side: check that the order belongs to the authenticated user, that the amount is within limits, that the ID is well-formed. Never assume the model got it right.
How this relates to the API and the Agents SDK
Actions are the Custom GPT surface for tool use. Under the hood, the same idea powers the OpenAI API, where you define tools as JSON schemas and the model returns a structured tool call for your code to execute. If you outgrow the GPT builder (you need custom logic between calls, your own UI, or orchestration across many tools), you move to the [Responses API](https://platform.openai.com/docs/api-reference/responses) or the [Agents SDK](https://platform.openai.com/docs/guides/agents-sdk), where you control the loop directly.
The migration path is clean: the descriptions and parameter schemas you wrote for an Action translate almost directly into tool definitions in code. Think of GPT Actions as the hosted, no-server-orchestration version of the same pattern. Prototype an integration as an Action, then graduate it to the Agents SDK when you need full control.
Debugging Actions
When a call misbehaves, work through these in order:
- Did the model call it at all? If it answered from guesswork, your
descriptionis too weak or too generic. Add the explicit "Use this when..." trigger sentence. - Wrong parameters? Check parameter
descriptionfields and types. Ambiguity here produces malformed requests. - Auth failures? Test the endpoint with the exact same key or token outside ChatGPT (a
curlcall) to isolate whether the problem is your auth or the GPT's config. - Schema rejected on save? The editor validates against OpenAPI 3.1. Paste your YAML into an external validator to find the offending line.
A fast curl sanity check before you ever touch the builder:
curl -s https://api.acme-shop.com/v1/orders/10428 \
-H "Authorization: Bearer $ACME_TOKEN"If that returns clean JSON, the GPT side is just schema and auth config.
Key Takeaways
- Write descriptions as prompts, not docs. The
operationId,summary, anddescriptionfields are how the model decides when and how to call your API. Include an explicit "Use this when..." sentence in each operation. - Match auth to identity needs. Use API Key for shared, read-only internal endpoints; use OAuth whenever each user should act as themselves or the action writes data.
- Treat the model as untrusted input. Validate every request server-side and mark write operations as consequential so users confirm before anything changes.
- Keep responses small and flat. Return only the fields the model needs; the response consumes context tokens and the model reasons over your field names.
- Prototype as an Action, graduate to the Agents SDK. The same schemas carry over, so start in the GPT builder and move to code when you need orchestration or custom logic between calls.
What to do, from this lesson
These actions are compiled in the role's Playbook.
- Write Action operationId, summary, and description as when-to-use prompts
- Use OAuth for user-scoped or write Actions; API keys only for shared read-only
Related articles
Recent articles from the blog that build on this lesson.