# How to Define API Endpoints in an OpenAI Plugin: A Complete Guide

> Learn how to define API endpoints for your OpenAI plugin. This guide details manifest files and OpenAPI specifications to expose your HTTP capabilities effectively.

- Repository: [OpenAI/plugins](https://github.com/openai/plugins)
- Tags: how-to-guide
- Published: 2026-07-06

---

**OpenAI plugins expose HTTP capabilities through a manifest file ([`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json)) that references an OpenAPI specification describing the available REST endpoints.**

The `openai/plugins` repository provides the reference architecture for extending ChatGPT with custom capabilities. To define API endpoints in an OpenAI plugin, you must declare an `api` block in your plugin manifest that points to a valid OpenAPI 3.0 specification hosted on a public HTTPS URL.

## Understanding the Plugin Manifest Structure

Every OpenAI plugin requires a manifest file located at [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json) in your repository root. This JSON file declares the plugin's metadata and, crucially, the location of its API specification.

The **api** block is the only required element for exposing HTTP endpoints. It contains two fields:
- `type`: Must be set to `"openapi"`
- `url`: A publicly accessible HTTPS URL pointing to your OpenAPI document

Additional optional blocks include `auth` for authentication flows and `hooks` for lifecycle events, but the `api` entry alone enables the model to discover and invoke your endpoints.

For a production example, examine the Zoom plugin manifest at [`plugins/zoom/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/zoom/.codex-plugin/plugin.json), which demonstrates how to structure the `api` and `auth` configurations for a real-world REST API.

## Creating the OpenAPI Specification

The OpenAPI specification enumerates every endpoint the model can call. This document must be hosted at the URL specified in your manifest and must use the OpenAPI 3.0.1 format.

Your specification requires three critical components:
1. **servers**: Defines the base URL for all API calls
2. **paths**: Lists each endpoint with HTTP methods, parameters, and response schemas
3. **operationId**: A unique identifier for each operation that the model uses to invoke the function

Below is a minimal example defining a single GET endpoint:

```yaml
openapi: 3.0.1
info:
  title: Weather Service
  version: "1.0"
servers:
  - url: https://api.myweather.com/v1
paths:
  /forecast:
    get:
      summary: Get a weather forecast
      operationId: getForecast
      parameters:
        - in: query
          name: city
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Forecast'
components:
  schemas:
    Forecast:
      type: object
      properties:
        temperature:
          type: number
        conditions:
          type: string

```

Reference the Zoom plugin's OpenAPI documentation at [`plugins/zoom/skills/rest-api/references/openapi.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/rest-api/references/openapi.md) to see how complex REST APIs structure their path hierarchies and security schemes.

## Wiring the Specification into the Manifest

Once your OpenAPI document is hosted on a public HTTPS endpoint, update [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json) to reference it:

```json
{
  "name": "weather-plugin",
  "description": "Provides real-time weather data",
  "api": {
    "type": "openapi",
    "url": "https://raw.githubusercontent.com/your-org/weather-plugin/main/openapi.yaml"
  },
  "auth": {
    "type": "none"
  }
}

```

Critical requirements for the URL:
- Must use **HTTPS** (TLS required)
- Must be publicly accessible without authentication
- Must remain stable (avoid temporary URLs in production)

For local development, you can use a tunneling service like `ngrok` to expose localhost temporarily, but remember to update the manifest with your production URL before submission.

## Handling Authentication

If your API requires authentication, add an `auth` block to your manifest instead of using `"type": "none"`. The OpenAI platform supports OAuth 2.0 and API key flows, automatically managing token exchange and injection.

For OAuth implementations, specify the client ID and required scopes:

```json
"auth": {
  "type": "oauth",
  "client_id": "YOUR_CLIENT_ID",
  "scopes": ["weather.read"]
}

```

For API key authentication, define the security scheme in your OpenAPI specification under `components/securitySchemes` and reference it from individual operations. The Zoom plugin demonstrates OAuth configuration in [`plugins/zoom/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/zoom/.codex-plugin/plugin.json) and provides additional context in [`plugins/zoom/skills/zoom-apps-sdk/references/oauth.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/references/oauth.md).

## Validating and Testing Your Endpoints

Before submitting your plugin, validate both the manifest and OpenAPI specification using the repository's built-in test harness.

Run the plugin evaluation suite from the repository root:

```bash
npm run test:plugin-eval

```

This command executes the test file located at [`plugins/plugin-eval/tests/plugin-eval.test.js`](https://github.com/openai/plugins/blob/main/plugins/plugin-eval/tests/plugin-eval.test.js), which verifies that your manifest syntax is valid, the OpenAPI document is reachable, and all `operationId` values are unique.

After validation, test functionality through the OpenAI Playground by enabling the Plugins toggle and loading your plugin. Issue natural language requests that should trigger your endpoints, such as asking for a weather forecast if you implemented the example above. The model will translate these requests into HTTP calls using the `operationId` mappings you defined.

## Summary

- Define API endpoints in an OpenAI plugin by creating a [`.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/.codex-plugin/plugin.json) manifest with an `api` block pointing to an OpenAPI specification.
- Host your OpenAPI 3.0 document on a public HTTPS URL with valid `paths`, `servers`, and unique `operationId` fields for each endpoint.
- Include an `auth` block in the manifest if your endpoints require OAuth or API key authentication.
- Validate your implementation using `npm run test:plugin-eval` before testing in the OpenAI Playground.
- Reference the Zoom plugin files in `openai/plugins` for production-ready examples of manifest structure and OpenAPI definitions.

## Frequently Asked Questions

### What file format should the OpenAPI specification use?

The specification must use **OpenAPI 3.0.1** format, written in either YAML or JSON. The document must include `servers`, `paths`, and `components/schemas` sections, with each operation defining a unique `operationId` that serves as the function name the model invokes.

### Can I use localhost URLs during development?

No, the manifest requires publicly accessible HTTPS URLs. For local development, use a tunneling service like `ngrok` to create a temporary public URL pointing to your localhost server. Remember to replace the temporary URL with your production endpoint before finalizing the plugin.

### How does the model know which endpoint to call for a specific user request?

The model reads your OpenAPI specification to understand available capabilities. When a user makes a relevant request, the model maps the intent to the appropriate `operationId` in your spec and constructs the HTTP request using the defined parameters, base URL from `servers`, and authentication details from the manifest's `auth` block.

### What validation errors commonly prevent plugin installation?

Common failures include non-HTTPS URLs in the `api.url` field, missing or duplicate `operationId` values in the OpenAPI spec, unreachable endpoints, and mismatches between the `name` field in the manifest and the repository directory name. Run `npm run test:plugin-eval` to catch these issues before submission.