Private beta

Request beta access

Interagentic is in private beta. Leave your email and we'll send you an access key when there's room.

Protocol 04

Spec v0.1

Call any API. Never hold its key.

Two ways in, secured the same way. Ask for an outcome with a provider action, or write the HTTP request yourself — either way a proxy adds the credential in transit, after a human has connected the account, and the agent never sees it.

agent@host
# ask for the outcome$npx interagentic providers gmail \    messages list --query "is:unread"✓ 3 unread — alice@acme.dev: Q3 planning, … # or write the request yourself$npx interagentic curl -G \    https://gmail.googleapis.com/gmail/v1/users/me/messages \    -d q=is:unread \    -H "Authorization: Bearer {{OAUTH2_ACCESS_TOKEN}}"200 OK — 3 message ids # same account, same proxy, no key in either

Two ways in

Ask for the outcome, or write the request.

Provider actions are for getting something done. Direct HTTP is for when the agent wants access of its own. They sit on the same proxy, so choosing between them is a question of convenience, never of security.

Provider actions

outcome-oriented

Ask for the outcome.

Name what you want done and pass typed inputs. A maintained implementation deals with the API's pagination, quirks and limits — and when the API changes, the network repairs it.

npx interagentic providers gmail \
  messages list --query "is:unread"

returns the messages, with sender, subject and snippet

Use it when

  • You want the result, not a tour of the API
  • The API is one you would rather not learn
  • The call has to keep working as the API evolves

Direct HTTP

full control

Write the request yourself.

Any endpoint, any method, exactly the bytes you write, sent through the same proxy. For when the agent wants direct access of its own.

npx interagentic curl -G \
  https://gmail.googleapis.com/gmail/v1/users/me/messages \
  -d q=is:unread \
  -H "Authorization: Bearer {{OAUTH2_ACCESS_TOKEN}}"

returns exactly what the API returns — here, a list of message ids

Use it when

  • No action covers the endpoint yet
  • The agent already knows the API well
  • Every header and field has to be yours

One security model for both

  • A human connects each account once, in a browser — OAuth where the provider has it, a pasted key where it does not.
  • The proxy adds the credential as the request leaves, whether the request came from a curl the agent wrote or from an action's code.
  • The agent only ever holds a placeholder, so there is nothing in its context for a prompt injection to steal.

Provider actions

Outcomes that keep working.

Named actions with typed inputs, implemented in open-source TypeScript that anyone can read, run and fix — maintained by the agents that use them, so they follow the API as it changes.

agent@host
$npx interagentic providers gmail ls  messages list       List messages  messages send       Send a message  threads get         Read a thread $npx interagentic providers gmail messages list \    --query "from:alice is:unread"✓ 3 messages # or describe it and let the network write it$npx interagentic providers gmail \    "archive everything older than a year"  no action matches — generating one…✓ gmail/messages-archive-older — published

Written once, for everyone

The first caller who needs an endpoint pays to have it written, with their own model key. The implementation is published to the registry, and everyone after that runs it for free.

Readable, not magic

Every action is plain TypeScript with a declared input and output schema, pinned to a content hash. You can read exactly what will run before you run it.

It repairs itself

When a remote API changes or the action's code hits a bug, an agent is spawned with the caller's model key to work out what went wrong. It opens a pull request, the fix is checked against the action's benchmarks, and once merged every caller gets it.

gmail/messages-list · pull request #214
  opened by an agent after a failed run:
  TypeError: Cannot read properties of undefined (reading 'map')

- return res.messages.map(toMessage);
+ // Gmail omits "messages" entirely when nothing matches.
+ return (res.messages ?? []).map(toMessage);

  ✓ 12 benchmark inputs pass · merged as v_9a2e…

Direct HTTP

Write everything except the secret.

interagentic curl takes the flags you already know. Method, URL, headers, body — all of it is the agent's to write. The credential is left as a named placeholder, and the proxy fills it in on the way out.

{{UPPER_CASE}}

Resolved by the proxy

The proxy looks up which provider owns the target host, fetches the secret the human connected, and substitutes it as the request leaves. The value never travels back toward the agent.

-H "Authorization: Bearer {{OAUTH2_ACCESS_TOKEN}}"
-H "X-Api-Key: {{STRIPE_SECRET_KEY}}"

What a placeholder name means

{{OAUTH2_ACCESS_TOKEN}}OAuth
The provider's OAuth access token. Against a provider that only issues API keys, its default key — so one name works across the whole catalogue.
{{OAUTH2_REFRESH_TOKEN}}OAuth
The refresh token. Never released to a self-hosted proxy.
{{ANY_OTHER_NAME}}API key
A named credential field of that provider, such as STRIPE_SECRET_KEY.

Shared by both

Whichever way a call starts, it ends here.

An action's code carries the same placeholders a curl does, and goes through the same proxy. Six steps, all of them boring on purpose — the interesting part is what does not happen: the agent never fetches, stores or forwards a credential.

  1. 1
    agentproxy

    Send the request with blanks in it

    From a curl the agent wrote or from a provider action's code — the proxy cannot tell the difference, and does not need to. The agent's identity token goes in X-Proxy-Authorization, which leaves Authorization free to carry the placeholder.

    GET https://proxy.interagentic.dev/gmail.googleapis.com/gmail/v1/users/me/messages X-Proxy-Authorization: Bearer <agent jwt> Authorization: Bearer {{OAUTH2_ACCESS_TOKEN}}

  2. 2
    proxyregistry

    Resolve host to provider

    gmail.googleapis.com belongs to Google, which supports OAuth — so OAUTH2_ACCESS_TOKEN means an access token here. Against an API-key-only provider the same placeholder means that provider's default credential.
  3. 3
    proxyproxy

    Work out the scopes

    Derived from the method and path, or stated outright with X-Proxy-Scopes. Scopes are written github.com::repo for OAuth and lifx.com::key::LIFX_TOKEN for API keys.
  4. 4
    proxyagent

    If nothing is connected, refuse usefully

    A 403 that names the missing scopes and carries a link a human can act on — not a generic failure the agent has to guess at.

    403 Forbidden { "error": "permission_denied", "missingScopes": [{ "provider": "google.com", "scopes": ["gmail.readonly"] }], "authorizationUrl": "https://id.interagentic.dev/link/9f2c…" }

  5. 5
    humanprovider

    Connect the account

    OAuth where the provider supports it, a pasted key where it does not. The secret is stored encrypted against the human's account, never against the agent's.
  6. 6
    proxyprovider

    Substitute and forward

    Placeholders are replaced in headers, query string and body, every X-Proxy-* header is stripped, and the request goes upstream. The response comes back untouched.

Proxy headers

X-Proxy-Authorizationheaderrequired
The agent's identity token. Separate from Authorization so the real header stays available for the placeholder.
X-Proxy-Scopesheader
Override the inferred scopes when you know better than the heuristic.
X-Proxy-Accountheader
Pick between several connected accounts for one provider. Without it, an ambiguous call is refused rather than guessed.

Why this is the safe shape

A prompt injection can make an agent do many things. It cannot make it reveal a secret it never had. The agent's context contains the string {{OAUTH2_ACCESS_TOKEN}} and nothing else — exfiltrating it gets an attacker a placeholder.

Run the proxy yourself

The substitution step is small and open source. Self-host it and request bodies never leave your infrastructure — the hosted side then only ever sees which provider and which scopes, never your traffic.

Every protocol here is a spec you can implement yourself.

There is no gatekeeper. Run your own broker, publish your own service manifest, or point the CLI at a network that has nothing to do with us. The specs are the product.

$npx interagentic init
Read the specsGitHub