How to build and extend external API connectors.
How to build and extend external API connectors.
Module: This skill applies when connector/full or connector/lite is active.
BEFORE building or testing any connector endpoint:
{connector}/openapi/ for downloaded API specsplan/specs/integrations/{system}.mdconnector/fullconnectors/{system}/
+-- AGENTS.md # How to work with this connector
+-- SKILL.md # What methods are available
+-- __init__.py # Clean public API
+-- config.py # Typed settings (BaseSettings)
+-- client.py # HTTP client, auth, rate limiting
+-- gateway.py # High-level facade (optional)
+-- services/
| +-- base.py # Shared patterns (pagination, error handling)
| +-- {entity}.py # One file per API entity (< 300 lines)
+-- openapi/ # Downloaded API specs
| Tier | File | Responsibility |
|---|---|---|
| Settings | config.py | Typed configuration via BaseSettings |
| Plumbing | client.py | HTTP transport, auth, retries, rate limiting |
| Translator | services/*.py | API-specific request/response translation |
| Brain | gateway.py | Business-level orchestration across services |
connector/lite)connectors/{system}/
+-- client.py # Everything in one file
+-- config.py # Settings
Use when the API has few endpoints and simple auth.
| Signal | Choice |
|---|---|
| > 5 endpoints | connector/full |
| Complex auth (OAuth, token refresh) | connector/full |
| Pagination, rate limiting | connector/full |
| Multiple entity types | connector/full |
| 1-5 simple endpoints | connector/lite |
| API key auth only | connector/lite |
| Started lite, growing complex | Upgrade to full |
class BaseService:
def __init__(self, client: HttpClient) -> None:
self._client = client
def _paginate(
self,
endpoint: str,
params: dict[str, str],
) -> Iterator[dict]:
"""Generic pagination handler."""
next_token: str | None = None
while True:
if next_token:
params["nextToken"] = next_token
response = self._client.get(endpoint, params=params)
yield from response["data"]
next_token = response.get("nextToken")
if not next_token:
break
from pydantic_settings import BaseSettings, SettingsConfigDict
class AmazonSettings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="AMAZON_")
client_id: str
client_secret: str
refresh_token: str
marketplace_id: str = "A1F83G8C2ARO7P"
BaseSettings (not hardcoded)When creating a new connector from scratch, follow this sequence:
Before writing any code:
openapi/)Use the decision table above. Default to lite — you can always upgrade later.
Create files in this order — each builds on the previous:
| Order | File | Dependencies |
|---|---|---|
| 1 | config.py | None — start here |
| 2 | client.py | Imports from config.py |
| 3 | services/base.py | Imports from client.py |
| 4 | services/{entity}.py | Extends base.py |
| 5 | gateway.py | Orchestrates services |
| 6 | __init__.py | Re-exports public API |
| 7 | AGENTS.md | Use CONNECTOR_AGENTS.md template |
| 8 | SKILL.md | Document public methods |
After the connector is functional:
.env.example| Don't | Do Instead |
|---|---|
| Code before reading API docs | Research first, code second |
| Put auth logic in services | Auth belongs in the client layer |
| Hardcode URLs or credentials | Use BaseSettings for all config |
| Ignore rate limits | Implement backoff in client layer |
| Skip AGENTS.md/SKILL.md | Doc the connector for future developers |
| Build full when lite suffices | Start lite, upgrade when complexity demands |