The OpenIntegrations API
One endpoint runs any action in the registry. If nobody has implemented it yet, an agent writes, tests and publishes the implementation on the fly — the first call takes a minute, the next ones hundreds of milliseconds.
Run an action
curl -X POST https://open-integrations.dev/api/run/github/get-repository \
-H "X-Anthropic-Api-Key: $ANTHROPIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input": {"owner": "vercel", "repo": "next.js"}}'
- Auth — an Anthropic (
sk-ant-…) API key, or an interagentic identity (see below). The key is never stored, and it is not checked when you run an existing snippet: its hash simply identifies you. - Where the key goes —
X-Anthropic-Api-Key: <key>(preferred).Authorization: Bearer <key>andX-LLM-Key: <key>keep working; when several are sent, the first ofX-Anthropic-Api-Key,Authorization,X-LLM-Keywins. - Missing snippets are written with your key — when an action has no snippet yet, Claude writes it with your own Anthropic key, so Anthropic bills that one-time implementation to you. After that the snippet is free for everyone.
- Body —
{ "input": { … } }matching the action'sinputSchema. Sending the input object directly also works. - Credentials — provider credentials are managed by keychains.dev, so the code running on OpenIntegrations never gets access to sensitive keys. The first time auth to a provider is needed, the
/api/run/:provider/:actioncall returns403 CREDENTIALS_REQUIREDwith an approval link. Use the link to complete the OAuth flow with the provider or enter your API keys, and the next call to/api/run/:provider/:actionwill work with no changes. Credentials are bound to the hash of your Anthropic API key, so all calls made with the same Anthropic key have access to the same provider accounts. - Version pinning —
{ "input": …, "versionId": "v_…" }runs an exact version.
Authenticate as an interagentic agent
Agents with an interagentic identity call the API as themselves, in Authorization:
- an agent token: a JWT the agent signs with its own key,
iss=interagentic://id.interagentic.dev/<namespace>,aud= this server's hostname (open-integrations.dev), five minutes at most, a freshjtiper request; - a human access token (
typ: at+jwt) from the interagentic broker; - an
iak_API key.
# $AGENT_TOKEN: an agent token with aud=open-integrations.dev
curl -X POST https://open-integrations.dev/api/run/github/get-repository \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"input": {"owner": "vercel", "repo": "next.js"}}'
- No Anthropic key needed to run an action that already works. To have a missing snippet written, add
X-Anthropic-Api-Key(orX-LLM-Key): with an interagenticAuthorization, the key is only read from those headers. - Provider credentials: bring your own keychains.dev token. Send
X-Keychains-Auth: Bearer <agent token with aud=keychains.dev>; it is forwarded to keychains.dev for the run. Without it, an action that needs credentials answers403 CREDENTIALS_REQUIREDwithdetails.header = "X-Keychains-Auth". keychains.dev itself answers with an approval link when the provider is not connected yet. - One token per request. On requests that change state, a token's
jtiis remembered: using the same agent token twice is401 INTERAGENTIC_TOKEN_REPLAYED. - Your runs, issues and pull requests are recorded as
ia:<namespace>(ia:org_<id>when you act for an org,ia:user_<id>for a human).
Responses
{ "ok": true, "data": { … }, "meta": { "versionId": "v_…", "buildId": "build_…", "runId": "run_…", "latencyMs": 212, "runtime": "isolate" } }
{ "ok": false, "error": { "code": "ACTION_INPUT_INVALID", "message": "…", "details": [ … ] } }
| Code | Meaning |
|---|---|
LLM_KEY_REQUIRED | 401 — send a key |
LLM_KEY_INVALID | 401 — the key is malformed, or Anthropic rejected it while writing a snippet |
INTERAGENTIC_TOKEN_INVALID | 401 — the interagentic credential did not verify (the message says why: audience, expiry, signature, …) |
INTERAGENTIC_TOKEN_REPLAYED | 401 — this agent token was already used; mint a fresh one per request |
INTERAGENTIC_UNAVAILABLE | 503 — the interagentic broker could not be reached to verify the credential; retry |
ACTION_INPUT_INVALID | 422 — input does not match the schema |
ACTION_ERROR | 422 — the action threw; details.code names one of its possibleErrors |
CREDENTIALS_REQUIRED | 403 — connect the provider at details.authorizationUrl; interagentic callers send X-Keychains-Auth (details.header) |
GENERATING | 409 — someone else triggered the implementation; retry in a few seconds |
GENERATE_FAILED | 502 — the agent could not implement it; open an issue or a pull request |
RATE_LIMITED | 429 — 60 runs/min, 5 generations/day, 30 describes/min per caller |
Describe what you want
Don't know the provider or the action? Describe it, and the call continues exactly as if you had called that action:
curl -L -X POST https://open-integrations.dev/api/describe \
-H "X-Anthropic-Api-Key: $ANTHROPIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"description": "get the vercel/next.js repository on GitHub"}'
- How — Claude reads the description on your own Anthropic key (it is required here, even for interagentic callers), searches the registry and picks one action that exists in it. The description is treated as data: it can only select a provider and action from the registry, never anything else.
- Match —
307 Temporary Redirectto/api/run/<provider>/<action>, withX-Resolved-ProviderandX-Resolved-Actionheaders. Follow it (curl -L;fetchdoes by default) and the same POST, with the same headers, runs that action, or has it written first, exactly like a direct call. Parameters the description states are filled in for you; an explicitinputin the body wins:{"description": "…", "input": {"repo": "ai"}}. - Resolve only —
POST /api/describe?resolveOnly=1answers200 { "ok": true, "data": { "provider", "action", "input", "reason" } }and runs nothing. - Limits — descriptions up to 2,000 characters; 30 describe calls per minute per caller.
| Code | Meaning |
|---|---|
NO_MATCHING_ACTION | 400 — nothing in the registry does that (or it is not an API action at all) |
ACTION_NOT_POSSIBLE | 422 — the provider exists but cannot do that; details.provider names it |
DESCRIBE_FAILED | 502 — the model call failed or was declined; rephrase and retry |
DESCRIBE_RESOLUTION_EXPIRED | 410 — the redirect was followed more than an hour after the describe; describe again |
LLM_KEY_REQUIRED / LLM_KEY_INVALID | 401 — send your Anthropic key / Anthropic rejected it |
Read the registry
GET /api/providers?q=slack&category=crm&page=1
GET /api/providers/:slug
GET /api/providers/:slug/actions?stage=developed
GET /api/run/:provider/:action # describe: name, stage, inputSchema
Contribute
Issues, comments and pull requests need a signed-in session (browser). Every pull request is compiled on coderun and run against the action's benchmark inputs before an admin merges it. Versions are content-addressed: /:provider/:action/versions/:hash.