How to Integrate Third-Party APIs into Codex Plugins: A Complete Guide
Integrating third-party APIs into Codex plugins requires defining skill metadata in a SKILL.md file, leveraging the reusable rest_request.py client for HTTP operations, and registering the skill in the .codex-plugin/plugin.json manifest to enable Codex discovery and execution.
Codex plugins extend AI capabilities by exposing skills that run inside a sandboxed Python interpreter. When you integrate third-party APIs into Codex plugins, you follow a standardized architecture that isolates network traffic to a single, well-tested module while declaring interfaces through structured metadata files.
Understanding the Codex Plugin Architecture
Codex plugins use a directory-based structure where skills are self-contained units. The system relies on three core components working together: metadata declaration, a generic HTTP client, and manifest registration.
Skill Metadata and Discovery
Each skill resides in its own subdirectory under skills/ and must contain a SKILL.md file. This file declares the skill's name, description, and input schema using YAML frontmatter. Codex reads this metadata to validate requests before execution.
The Generic REST Client
Rather than importing heavy HTTP libraries for every integration, the repository provides rest_request.py. This compact client handles GET and POST requests, JSON versus text responses, pagination-style truncation, and optional raw-output saving. Skill authors import this module and call the execute() function with a standardized payload.
Step-by-Step Integration Process
Follow this pattern to add any RESTful service to your Codex plugin without modifying the core framework.
Step 1: Define the Skill Metadata (SKILL.md)
Create a SKILL.md file in your skill directory that specifies the expected input schema. This document tells Codex what parameters the skill accepts, including base_url, path, and params.
name: uniprot-skill
description: Query UniProt for protein information.
input_schema:
type: object
properties:
base_url:
const: https://rest.uniprot.org
path:
type: string
enum:
- uniprotkb/search
- uniprotkb/{accession}
params:
type: object
additionalProperties: true
required:
- base_url
- path
The schema enforces type safety by requiring specific fields while allowing flexible query parameters through additionalProperties: true.
Step 2: Reuse the Generic REST Client (rest_request.py)
Implement a Python wrapper that imports the shared client from scripts/rest_request.py. The wrapper reads the JSON payload from standard input, passes it to the execute() function, and returns the normalized result.
#!/usr/bin/env python3
import json
import sys
from pathlib import Path
# Import the generic client used across the plugin ecosystem
sys.path.append(str(Path(__file__).parent / "scripts"))
from rest_request import execute, error
def main() -> int:
try:
payload = json.load(sys.stdin)
except Exception as exc:
sys.stdout.write(json.dumps(error("invalid_json", f"Could not parse JSON input: {exc}")))
return 2
# Delegate HTTP logic to the reusable client
output = execute(payload)
sys.stdout.write(json.dumps(output))
return 0 if output.get("ok") else 1
if __name__ == "__main__":
raise SystemExit(main())
The execute() function in rest_request.py builds the full URL, merges headers, applies timeouts, and returns a normalized JSON document containing the HTTP status code, record count, and response data.
Step 3: Register the Skill in the Plugin Manifest
Add the skill to .codex-plugin/plugin.json so Codex can discover it during initialization. The manifest maps skill names to their directory paths.
{
"name": "uniprot",
"version": "0.1.0",
"skills": [
{
"name": "uniprot-skill",
"path": "skills/uniprot-skill"
}
]
}
As shown in the Daloopa plugin example at plugins/daloopa/.codex-plugin/plugin.json, this registration enables Codex to locate and load your skill when users request it.
Complete Integration Example: UniProt API
Here is a working implementation that queries the UniProt protein database using the patterns described above.
Creating the SKILL.md Schema
The metadata file at plugins/life-science-research/skills/uniprot-skill/SKILL.md defines the contract between Codex and the external API. It specifies that base_url is constant while path and params vary by request.
Implementing the Python Wrapper
The file plugins/life-science-research/skills/uniprot-skill/scripts/run_uniprot.py serves as the entry point. It performs minimal logic—parsing stdin and delegating to rest_request.execute()—making it reusable for other REST endpoints by changing only the input payload.
Testing the Integration
Invoke the skill by piping a JSON payload that matches the schema:
cat <<'EOF' | python plugins/life-science-research/skills/uniprot-skill/scripts/run_uniprot.py
{
"base_url": "https://rest.uniprot.org",
"path": "uniprotkb/search",
"method": "GET",
"params": {
"query": "gene:TP53 AND organism_id:9606",
"fields": "accession,gene_names",
"size": 5,
"format": "json"
},
"response_format": "json",
"max_items": 5,
"max_depth": 2
}
EOF
The rest_request.py client returns a normalized response:
{
"ok": true,
"source": "rest-uniprot-org",
"path": "uniprotkb/search",
"method": "GET",
"status_code": 200,
"record_path": "results",
"record_count_returned": 5,
"record_count_available": 5,
"truncated": false,
"records": [
{ "accession": "P04637", "gene_names": "TP53" }
],
"warnings": []
}
Security and Safety Features
The integration pattern includes multiple safeguards. The rest_request.py client validates input types, sanitizes strings, and enforces limits on returned data through max_items and max_depth parameters. When the save_raw option is enabled, the client stores unprocessed responses to temporary files rather than loading massive payloads into memory. Because all third-party network traffic routes through this single module, you can audit, unit-test, and secure integrations centrally without reviewing every individual skill implementation.
Summary
- Define metadata in
SKILL.mdto declare the skill's interface and input schema for Codex validation. - Reuse
rest_request.pyas the centralized HTTP client to handle GET/POST requests, response normalization, and pagination truncation across all third-party integrations. - Register skills in
.codex-plugin/plugin.jsonto enable discovery and loading by the Codex interpreter. - Implement thin wrappers like
run_uniprot.pythat parse stdin and delegate to the generic client, keeping skill-specific code minimal and testable. - Leverage built-in safety features including input validation, string sanitization, and response size limits to maintain security within the sandboxed environment.
Frequently Asked Questions
What is the purpose of the SKILL.md file in Codex plugins?
The SKILL.md file serves as the skill's contract with Codex, defining the name, description, and input schema using YAML frontmatter. Codex reads this file to validate user requests against the expected parameters before invoking the skill's Python wrapper, ensuring type safety and proper API usage.
How does the generic REST client handle large API responses?
The rest_request.py client implements pagination-style truncation using the max_items and max_depth parameters. It caps the number of returned records and nesting depth in JSON responses, preventing memory exhaustion. Optionally, setting save_raw: true streams the full response to a temporary file rather than loading it into the sandboxed interpreter's memory.
Where does Codex discover available plugin skills?
Codex discovers skills by reading the .codex-plugin/plugin.json manifest file at the plugin root. This JSON file contains a skills array that maps skill names to their directory paths, allowing Codex to locate the corresponding SKILL.md and executable scripts during initialization.
Can I use custom HTTP libraries instead of rest_request.py?
While the architecture allows custom implementations, the repository design encourages reusing rest_request.py to maintain consistency and security. This dependency-light client is used across dozens of integrations (UniProt, NCBI, Opentargets) and provides centralized handling of timeouts, headers, and response normalization that custom libraries would need to reimplement.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →