# How to Integrate with Third-Party Services Using OpenAI Plugins: A Complete Developer's Guide

> Discover how to integrate third-party services with OpenAI plugins. This developer's guide covers the architecture and implementation for ChatGPT function calls.

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

---

**OpenAI Plugins provide a standardized architecture consisting of a JSON manifest, server-side skills, and runtime configuration that transforms any third-party REST API into a discoverable, type-safe function call for ChatGPT.**

The `openai/plugins` repository defines a protocol for connecting external services like SendGrid, Notion, and Google Drive to OpenAI's language models. By implementing a minimal manifest and skill handler, you can integrate with third-party services using OpenAI plugins to expose secure, sandboxed capabilities to ChatGPT users without arbitrary code execution risks.

## The Three Core Components

Every plugin consists of three independent files that separate concerns and enable version control.

| Component | Role | Key Source File |
|-----------|------|-----------------|
| **Manifest** | Declares the plugin name, description, authentication method, and the list of OpenAI-compatible functions it offers. | `plugins/<service>/.codex-plugin/plugin.json` |
| **Skills** | Implements the server-side logic that receives a function request, calls the third-party API, and returns a JSON response. | `plugins/<service>/skills/.../SKILL.md` |
| **App Config** | Supplies runtime settings (e.g., base URL, OAuth scopes, webhook URLs) that the hosting platform uses to launch the plugin. | `plugins/<service>/.app.json` |

This architecture ensures **safety first** by restricting the plugin to a fixed set of functions with strict JSON schemas, while maintaining **discoverability** so the model can enumerate capabilities dynamically.

## Step-by-Step Integration Workflow

Follow these six steps to bridge a third-party service to ChatGPT:

1. **Create a manifest** – Use the **plugin-creator** skill located at `.agents/skills/plugin-creator` to scaffold a new plugin. The manifest tells OpenAI how the plugin should be discovered and what credentials it needs.

2. **Implement the skill** – Write a tiny HTTP handler (often in Python, Node, or Go) that receives the OpenAI-generated request, validates the arguments, forwards them to the target service's REST endpoint, and maps the response back to the OpenAI schema.

3. **Define OpenAI function specifications** – In the manifest's `functions` section, describe each callable operation with name, description, and parameters. ChatGPT automatically translates user intent into a call to one of these functions.

4. **Configure authentication** – Most services require an API key or OAuth token. The manifest can request a secret (`"type": "api_key"`). At deployment time, store the secret in the platform's secret manager; the plugin runtime injects it into the handler.

5. **Deploy** – Push the plugin directory to a hosting platform that supports Codex plugins (e.g., Vercel, Railway, or a custom Docker container). The platform reads the [`.app.json`](https://github.com/openai/plugins/blob/main/.app.json) to spin up the service.

6. **Register** – Add the plugin's URL to the OpenAI Plugin Marketplace ([`.agents/plugins/marketplace.json`](https://github.com/openai/plugins/blob/main/.agents/plugins/marketplace.json)). Once approved, ChatGPT users can enable the plugin in their chat UI and start invoking its functions.

## Implementation Examples

### Minimal Manifest for SendGrid

The [`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json) file defines the contract between OpenAI and your service. This example from [`plugins/sendgrid/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/sendgrid/.codex-plugin/plugin.json) exposes an email-sending function:

```json
{
  "schema_version": "v1",
  "name_for_human": "SendGrid Email",
  "name_for_model": "sendgrid_email",
  "description_for_human": "Send transactional emails via SendGrid",
  "description_for_model": "Provides a function to send an email with subject, body, and recipient.",
  "auth": {
    "type": "api_key",
    "instructions": "Add your SendGrid API key to the environment variable SENDGRID_API_KEY."
  },
  "api": {
    "type": "openapi",
    "url": "https://raw.githubusercontent.com/openai/plugins/main/plugins/sendgrid/openapi.yaml"
  },
  "functions": [
    {
      "name": "send_email",
      "description": "Send an email through SendGrid",
      "parameters": {
        "type": "object",
        "properties": {
          "to": { "type": "string", "description": "Recipient email address" },
          "subject": { "type": "string", "description": "Email subject line" },
          "content": { "type": "string", "description": "Plain‑text email body" }
        },
        "required": ["to", "subject", "content"]
      }
    }
  ]
}

```

### Python Flask Skill Handler

The skill implementation lives under [`plugins/sendgrid/skills/send_email/skill.py`](https://github.com/openai/plugins/blob/main/plugins/sendgrid/skills/send_email/skill.py) (structure shown in the repository's [`SKILL.md`](https://github.com/openai/plugins/blob/main/SKILL.md)). This handler receives the function arguments from OpenAI, validates them, and proxies the request to SendGrid:

```python
import os
import requests
from flask import Flask, request, jsonify

app = Flask(__name__)

SENDGRID_API_KEY = os.getenv("SENDGRID_API_KEY")
SENDGRID_ENDPOINT = "https://api.sendgrid.com/v3/mail/send"

@app.route("/skill", methods=["POST"])
def skill():
    data = request.json  # OpenAI passes the function arguments here

    # Validate required fields (the manifest guarantees they exist)

    to = data["to"]
    subject = data["subject"]
    content = data["content"]

    payload = {
        "personalizations": [{"to": [{"email": to}]}],
        "from": {"email": "noreply@example.com"},
        "subject": subject,
        "content": [{"type": "text/plain", "value": content}],
    }

    resp = requests.post(
        SENDGRID_ENDPOINT,
        json=payload,
        headers={"Authorization": f"Bearer {SENDGRID_API_KEY}"}
    )
    if resp.status_code != 202:
        return jsonify({"error": resp.text}), resp.status_code

    return jsonify({"result": f"Email sent to {to}"})


if __name__ == "__main__":
    app.run(port=8000)

```

### Invoking the Plugin from ChatGPT

Once deployed, ChatGPT automatically translates natural language into function calls. The model infers the need to call `send_email`, fills the required parameters, and invokes the skill:

```json
{
  "model": "gpt-4o",
  "messages": [
    {"role": "user", "content": "Email my manager a quick note about the project status."}
  ],
  "plugins": [
    {"url": "https://my-hosted-plugin.example.com"}
  ]
}

```

## Critical Source Files

These files from the `openai/plugins` repository illustrate the full lifecycle from manifest definition to deployment:

- **[`README.md`](https://github.com/openai/plugins/blob/main/README.md)** – High-level overview of the repository and plugin architecture.
- **[`.agents/skills/plugin-creator/SKILL.md`](https://github.com/openai/plugins/blob/main/.agents/skills/plugin-creator/SKILL.md)** – Guides you through scaffolding a new plugin (manifest, skills, app config).
- **[`plugins/sendgrid/.codex-plugin/plugin.json`](https://github.com/openai/plugins/blob/main/plugins/sendgrid/.codex-plugin/plugin.json)** – Concrete example of a manifest for a third-party service.
- **[`plugins/sendgrid/.app.json`](https://github.com/openai/plugins/blob/main/plugins/sendgrid/.app.json)** – Runtime configuration that tells the host how to launch the SendGrid skill.
- **[`plugins/sendgrid/skills/send_email/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/sendgrid/skills/send_email/SKILL.md)** – Shows the expected folder layout and entry-point for skill implementation.
- **[`plugins/notion/skills/notion-spec-to-implementation/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/notion/skills/notion-spec-to-implementation/SKILL.md)** – Fully-fledged plugin demonstrating complex OAuth flows and pagination handling.

## Summary

- **Three files** define a plugin: the manifest ([`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json)), skill implementation, and app config ([`.app.json`](https://github.com/openai/plugins/blob/main/.app.json)).
- **Safety is enforced** through strict JSON schemas in the manifest that prevent arbitrary code execution.
- **Authentication** is handled via environment variables or OAuth flows defined in the manifest and injected at runtime.
- **Discovery is automatic** – ChatGPT enumerates capabilities from the manifest's `functions` array to translate user intent into API calls.
- **Deployment** requires hosting the skill and registering the URL in the OpenAI Plugin Marketplace.

## Frequently Asked Questions

### What authentication methods are supported for third-party integrations?

OpenAI plugins support **API keys** and **OAuth tokens**. You declare the type in the manifest's `auth` section (e.g., `"type": "api_key"`). The hosting platform's secret manager injects these credentials into the skill's environment at runtime, keeping sensitive data out of source control.

### How does ChatGPT discover which functions a plugin provides?

ChatGPT reads the `functions` array defined in `plugins/<service>/.codex-plugin/plugin.json`. Each function includes a name, description, and JSON Schema parameters. The model uses these descriptions to match user intent (like "send an email") to the appropriate function call, automatically extracting arguments such as recipient addresses or subject lines from the conversation context.

### What is the difference between the manifest and the skill?

The **manifest** ([`plugin.json`](https://github.com/openai/plugins/blob/main/plugin.json)) is a static declaration that tells OpenAI what your plugin does and how to authenticate it. The **skill** is the executable code (typically a Python Flask or Node.js handler) that receives the function call from OpenAI, executes the actual HTTP request to the third-party service (e.g., SendGrid), and returns the formatted response. They are separate concerns to enable independent versioning and deployment.

### Can I integrate any REST API with OpenAI plugins?

Yes. Any REST API that accepts HTTP requests and returns JSON can be wrapped as a plugin. You define the mapping between OpenAI's function schema and the third-party API's endpoints in your skill implementation. Complex workflows involving pagination, OAuth flows, or batch operations are supported, as demonstrated in [`plugins/notion/skills/notion-spec-to-implementation/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/notion/skills/notion-spec-to-implementation/SKILL.md).