How to Integrate with External APIs Using OpenAI Plugins: A Complete Technical Guide

OpenAI Plugins enable language models to invoke external HTTP APIs through a declarative framework that combines JSON manifests, OpenAPI specifications, and Python wrapper scripts to map natural language intents to concrete function calls.

The openai/plugins repository provides a composable, file-system-driven architecture for connecting large language models to third-party services. By leveraging declarative configuration files and lightweight implementation scripts, developers can expose any REST API to the model without modifying core runtime code.

Architecture of OpenAI Plugins for External API Integration

The framework separates concerns into distinct components that together describe how to integrate with external APIs using OpenAI plugins. Each component serves a specific role in the discovery, authentication, and execution pipeline.

Plugin Manifest and OpenAPI Specification

The Plugin Manifest (.app.json) serves as the entry point for every plugin. Located at paths like plugins/figma/.app.json, this JSON file declares the plugin package metadata, version, and the OpenAPI specification that describes the external service's HTTP endpoints.

The OpenAPI spec embedded in the manifest defines available paths, parameters, request/response schemas, and data types. This specification is either included directly in the manifest or referenced from a separate openapi.yaml file, providing the model with a machine-readable contract of the external API's capabilities.

Authentication Configuration

The Authentication Config describes credential acquisition and injection methods. As documented in plugins/box/skills/box/references/auth-and-setup.md, the framework supports multiple authentication flows including OAuth2 client-credentials, API keys, and bearer tokens.

This configuration specifies how the runtime should obtain access tokens and where to inject them in outbound HTTP requests—whether as query parameters, headers, or cookie values.

Skills, Functions, and Agent YAML

A skill is a reusable unit that maps natural-language intents to concrete function calls. Each skill contains:

  • Metadata (evals.json or metadata.json) that tells the model which function name, arguments, and return types to use
  • Agent YAML (agents/openai.yaml) that constructs the OpenAI function-calling schema visible to the model

The file plugins/box/skills/box/agents/openai.yaml demonstrates how argument definitions are pulled from skill metadata and wired to implementation scripts, creating the bridge between the model's function-calling interface and the external API.

Implementation Scripts and Runtime Dispatcher

Implementation Scripts are Python or Node.js files that receive parsed arguments, perform actual HTTP requests, and return JSON-serializable responses. The file plugins/box/skills/box/scripts/box_rest.py provides a real-world example of a wrapper that communicates with Box's Content API.

The Runtime Dispatcher, implemented in .agents/skills/plugin-creator/scripts/create_basic_plugin.py, loads the manifest, spins up a FastAPI server, and registers functions with the OpenAI API. This generic agent eliminates the need to build custom servers for each integration.

Execution Flow: From User Prompt to API Response

When you integrate with external APIs using OpenAI plugins, the execution follows a precise six-step flow:

  1. The user submits a prompt, and the chat model receives the function-calling schema originating from agents/openai.yaml
  2. The model decides to invoke a specific function (e.g., list_documents)
  3. The plugin runtime receives the call, unmarshals arguments, and executes the corresponding implementation script
  4. The script builds an HTTP request using the OpenAPI spec, adds the appropriate auth header (API key or OAuth token), and forwards it to the external service
  5. The response is transformed into the declared return schema and sent back to the model as the function result
  6. The model integrates the result into its next reply, completing the external API integration loop

Because the system is declarative, adding a new third-party API requires only creating new configuration files and a thin wrapper script—no changes to the core runtime.

Complete Example: Building a Weather Plugin

Below is a self-contained example demonstrating how to integrate with external APIs using OpenAI plugins to call the OpenWeatherMap API.

First, create the plugin manifest at plugins/weather/.app.json:

{
  "name": "weather",
  "version": "0.1.0",
  "openapi": {
    "openapi": "3.0.0",
    "info": {
      "title": "Weather API",
      "version": "1.0"
    },
    "paths": {
      "/weather": {
        "get": {
          "parameters": [
            { "name": "q", "in": "query", "required": true, "schema": { "type": "string" } },
            { "name": "appid", "in": "query", "required": true, "schema": { "type": "string" } }
          ],
          "responses": {
            "200": {
              "description": "Current weather",
              "content": {
                "application/json": {
                  "schema": { "$ref": "#/components/schemas/WeatherResponse" }
                }
              }
            }
          }
        }
      }
    },
    "components": {
      "schemas": {
        "WeatherResponse": {
          "type": "object",
          "properties": {
            "temp_c": { "type": "number" },
            "description": { "type": "string" }
          },
          "required": ["temp_c", "description"]
        }
      }
    }
  },
  "auth": {
    "type": "apiKey",
    "in": "query",
    "name": "appid"
  }
}

Next, define the function schema at plugins/weather/skills/get_current/agents/openai.yaml:

name: get_current_weather
description: Retrieve the current temperature for a city.
parameters:
  type: object
  properties:
    city:
      type: string
      description: Name of the city (e.g., "Paris")
required:
  - city

Finally, implement the request logic at plugins/weather/skills/get_current/scripts/weather.py:

import os
import requests

def get_current_weather(city: str) -> dict:
    api_key = os.getenv("WEATHER_API_KEY")
    url = "https://api.openweathermap.org/data/2.5/weather"
    resp = requests.get(url, params={"q": city, "appid": api_key, "units": "metric"})
    data = resp.json()
    return {
        "temp_c": data["main"]["temp"],
        "description": data["weather"][0]["description"],
    }

When a user asks "What's the weather in Tokyo?", the model automatically calls get_current_weather with "Tokyo" as the argument, the plugin hits OpenWeatherMap, and the model embeds the temperature in its reply.

Key Implementation Files in the Repository

The openai/plugins repository contains several reference implementations that demonstrate production patterns for external API integration:

Summary

  • OpenAI Plugins use a declarative architecture to expose external HTTP APIs to language models through function calling
  • The Plugin Manifest (.app.json) and OpenAPI specification define the API contract, while Agent YAML files create the function schema visible to the model
  • Implementation scripts in Python or Node.js handle the actual HTTP requests, authentication, and response transformation
  • Adding new external services requires only creating new configuration files and wrapper scripts in the plugins/ directory, with no changes to the core runtime
  • The framework supports multiple authentication schemes including OAuth2 and API keys, configured declaratively in the manifest

Frequently Asked Questions

How does the OpenAI plugin runtime know which external API endpoint to call?

The runtime consults the OpenAPI specification embedded in the plugin manifest (.app.json) to determine the exact HTTP method, path, parameters, and data schemas for each endpoint. When the model invokes a function, the implementation script (such as plugins/box/skills/box/scripts/box_rest.py) constructs the request using these specifications, ensuring the external API receives properly formatted calls.

What authentication methods are supported when integrating external APIs?

The framework supports OAuth2 client-credentials, API keys, and bearer tokens according to the repository's authentication configuration files. As shown in plugins/box/skills/box/references/auth-and-setup.md, credentials can be injected as query parameters, headers, or cookies based on the auth block in the manifest, with sensitive values stored in environment variables rather than committed to source control.

Can I use languages other than Python for the implementation scripts?

While the examples in the repository primarily use Python (such as plugins/zotero/skills/zotero/scripts/zotero.py), the architecture is language-agnostic. The runtime dispatcher executes the script specified in the skill configuration, meaning Node.js, Go, or any executable can handle the HTTP request logic as long as it accepts JSON arguments and returns JSON-serializable output.

Where should I store sensitive API keys and credentials?

Sensitive credentials should be stored in environment variables referenced by your implementation scripts, as demonstrated in the weather example where WEATHER_API_KEY is read via os.getenv(). Never commit API keys, OAuth secrets, or access tokens to the repository; instead, document the required environment variables in a references/ markdown file so users know how to configure their local environment.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →