New:Microsoft Teams Notifications Are Now Available in Socket.Learn more
Get Started

@interagentic/sdk

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@interagentic/sdk

Client SDK for Interagentic — federated bot identity, authentication, and payments

latest
Source
npmnpm
Version
0.1.0
Version published
Weekly downloads
0
Maintainers
1
Weekly downloads
 
Created
Source

@interagentic/sdk

Client SDK for Interagentic — agent identity, signed tokens and authenticated requests from Node.js.

Your agent gets an identity on a broker, keeps its key fresh, and proves who is calling — with a token scoped to the one server it is talking to.

Install

npm install @interagentic/sdk

Quick start

import { InteragenticClient } from '@interagentic/sdk';

const client = new InteragenticClient();

// The first call registers a namespace and stores its key in ~/.interagentic/.
// Later calls rotate the key before it goes stale.
const res = await client.fetch('https://api.github.com/user/repos', {
  headers: { Authorization: 'Bearer {{OAUTH2_ACCESS_TOKEN}}' },
});

client.fetch goes through the credential proxy (https://keychains.dev by default): {{PLACEHOLDER}}s are replaced by the proxy with credentials a human connected, and never travel back to your process. For a script that needs nothing else, interagenticFetch(url, init) does the same through a shared default client.

Tokens

// For a service that verifies agent tokens itself:
const token = await client.generateToken(undefined, { audience: 'api.example.com' });
await fetch('https://api.example.com/v1/orders', { headers: { Authorization: `Bearer ${token}` } });

Every token is a JWT signed by the agent's own key:

Value
header{ "alg": "EdDSA" | "ES256" | "RS256", "typ": "JWT", "kid": "<key id>" }
issinteragentic://<broker host>/<namespace> (port kept when non-default)
subsame as iss, or interagentic://<broker host>/org_<id> when acting for an org
audthe hostname of the server being called — options.audience, reduced to its hostname; the broker's hostname by default
iat, expexp = iat + 300
jtia random UUID, unique per token

Mint one token per request rather than caching it. generateToken(claims, { actAs: false }) signs as the agent even while it acts for an org; extra claims are added but can never override the ones above. Every call the SDK makes to the broker uses aud = the broker's hostname.

With a stable API key (iak_… in INTERAGENTIC_STABLE_API_KEY or credentials.json), generateToken returns that key instead. Stable keys expire — 90 days from createApiKey, or whatever { expiresIn } (seconds, up to a year) asks for. Nothing renews one: read expiresAt and hand the holder a new key before it passes.

Requests

MethodSendsToken
client.fetch(url, init)through the proxy; approval, permission, link, payment and lock answers are thrown as typed errorsX-Proxy-Authorization, aud = proxy host
client.proxyFetch(url, init, { scopes, account, stream })the same, but returns every response as isX-Proxy-Authorization, aud = proxy host
client.fetchDirect(url, init)straight to a service that verifies agent tokens (https, or http on loopback)Authorization, aud = target host

Proxied requests carry the target both in the path (<proxy>/<host[:port]>/<path>) and in X-Proxy-Target-URL, so ports and http://localhost targets survive. Redirects are followed by sending the next hop through the proxy again (or, for fetchDirect, only within the same origin), so the token never reaches a host it was not minted for. A 401 stale-key answer, or a key_too_old challenge (WWW-Authenticate: Interagentic … error="key_too_old"), rotates the key and retries once.

client.supportsInteragenticAuth(url) tells whether a target publishes /.well-known/interagentic/services.json with "auth": "interagentic" (cached per origin in the state directory).

detectHumanAction(status, headers, body) classifies a response that needs a person — a 402 with its price and approval link, a 403 permission or link refusal, a 423 lock. client.waitForApproval(url) then polls until the approval is granted (client.waitForLink() for a human link).

Services v1

const result = await client.executeServiceAction({
  domain: 'popcorn.club',                 // or a short name: 'mongo' → mongo.interagentic.dev
  command: ['orders', 'refunds', 'create'],
  params: { id: 'ord_8fJ2', reason: 'damaged', amount: 4.5, notify: true },
  jsonMode: true,
});
// POST https://popcorn.club/api/v1/orders/ord_8fJ2/refunds?notify=true
// { "reason": "damaged", "refund": { "amount": 4.5 } }

fetchServiceIndex(domain) and fetchServiceAction(domain, command) read /.well-known/interagentic/services.json and services/<segment>/…/<leaf>.json. executeServiceAction validates the arguments against the action's parameters (throwing ServiceArgumentError before any request), renders the request from its templates, signs a token with aud = the service's hostname, and returns the raw response. files: ['./dist'] uploads files under the action's files rules.

The building blocks are exported for other clients: resolveServiceCommand (the command model's greedy resolution), prepareServiceArguments, renderServiceRequest (request templates, §4 of the spec) and collectServiceFiles.

Key rotation

Keys rotate automatically before they go stale; client.keys.rotate() rotates on demand. Rotation follows the broker contract and is safe to run concurrently:

  • an exclusive lock on rotation.lock in the state directory (a rotation another process finished while this one waited is returned instead of chaining a second one);
  • the new private key is written to private.pem.pending before the broker is called;
  • the request is signed by the current key and carries a proof of possession signed by the new one;
  • the broker answers with a new key id, written to identity.json together with the promoted key; 409 (the key is already current) counts as success;
  • 429 is retried with backoff.

If the process dies mid-rotation, the next run tries the pending key first, looks for it in the namespace's published key set, and otherwise replays the rotation idempotently. It never signs an ordinary request with a key that may have been rotated out — that is what makes a broker lock the namespace.

Configuration

OptionEnvironment variableDefault
serverUrlINTERAGENTIC_BROKER (or INTERAGENTIC_SERVER_URL)https://id.interagentic.dev
stateDirINTERAGENTIC_STATE_DIR~/.interagentic
proxyUrlINTERAGENTIC_PROXY_URLhttps://keychains.dev
algorithmEdDSA (ES256, RS256)
rotationTTL15 minutes
inviteTokenINTERAGENTIC_INVITE_TOKEN

INTERAGENTIC_ACT_AS makes tokens act for an org; INTERAGENTIC_STABLE_API_KEY switches to a stable API key.

State files

~/.interagentic/                 (0700)
├── identity.json                broker, namespace, key id, algorithm, rotation time (0600)
├── private.pem                  the private key (0600)
├── private.pem.pending          write-ahead log of an in-flight rotation (0600)
└── rotation.lock                held while rotating

Errors

ClassCodeHTTPWhen
InteragenticErrorvariesvariesBase class: code, message, statusCode, actionUrl
NamespaceLockedErrorNAMESPACE_LOCKED423A human must unlock the namespace
PaymentRequiredErrorPAYMENT_REQUIRED402credits (decimal string), description, actionUrl
InsufficientPermissionErrorINSUFFICIENT_PERMISSION403A permission or scope is missing; missingScopes
LinkRequiredErrorLINK_REQUIRED403A human has to link the agent or approve a credential
ServiceArgumentErrorINVALID_ARGUMENTSService arguments failed validation; problems

Network failures are reported as InteragenticError with code NETWORK_ERROR.

Tests

npm test

The tests run against local mock servers only (a broker that implements the rotation contract, a proxy and a Services v1 service); a network guard fails any request to a non-local host.

License

MIT

Keywords

interagentic

FAQs

Package last updated on 21 Sep 2026

Related posts