SDK
@interagentic/sdk — an agent identity, signed tokens and authenticated requests from Node.js.
@interagentic/sdk is the library the interagentic CLI is built on. It gives a
Node.js process an identity on a broker, keeps that identity's key fresh, and
produces the credential that proves who is calling.
npm install @interagentic/sdkThe package ships ESM and CommonJS builds with type declarations. It keeps its
state on disk through node:fs, so it runs in Node.js, not in a browser.
Quick start
import { InteragenticClient } from "@interagentic/sdk";
const client = new InteragenticClient();
// The first call registers a namespace and stores its key.
// Later calls rotate the key before it goes stale.
const res = await client.fetch("https://api.example.com/v1/items");
console.log(res.status, await res.json());For a script that needs nothing else, interagenticFetch(url, init) does the
same through a shared default client:
import { interagenticFetch } from "@interagentic/sdk";
const res = await interagenticFetch("https://api.example.com/v1/items");new InteragenticClient(options?)
Every option is optional. An option passed to the constructor wins over the environment variable.
| Option | Environment variable | Default | Purpose |
|---|---|---|---|
serverUrl | INTERAGENTIC_SERVER_URL | https://id.interagentic.dev | Identity broker |
stateDir | INTERAGENTIC_STATE_DIR | ~/.interagentic | Where the identity and keys live |
proxyUrl | INTERAGENTIC_PROXY_URL | https://keychains.dev | Credential proxy used by fetch |
algorithm | — | "EdDSA" | Key type for new keys: "EdDSA" (Ed25519) or "ES256" |
rotationTTL | — | 15 | Minutes a key stays fresh before it must be rotated |
inviteToken | INTERAGENTIC_INVITE_TOKEN | — | Used on first registration: register under an inviting namespace, or join an organization |
The state directory holds the same files as the CLI's — see
state on disk — so a program and the CLI on one
machine share one identity. A stable API key is read from
INTERAGENTIC_STABLE_API_KEY, or from credentials.json in the state
directory.
client.fetch(url, init?)
Takes the same arguments as the global fetch and returns a standard
Response.
- The request is sent through the credential proxy:
urlis rewritten to<proxyUrl>/<host><path>?<query>, and the token fromgenerateToken()is sent inX-Proxy-Authorization: Bearer …. Your own headers and body pass through unchanged. - A
401with codeKEY_STALErotates the key and retries once. - A
403with codewrong_proxyretries once through the proxy the response names. - Approval, permission, link, payment and lock responses are thrown as typed errors. Any other status is returned for you to handle.
client.generateToken(claims?)
Returns the credential for this agent, as a string ready for
Authorization: Bearer … on a service that accepts it directly.
- With a stable API key configured, it returns that key unchanged.
- Otherwise it registers a namespace if the state directory has none,
completes a rotation that was interrupted, rotates the key when it is within
a minute of going stale, and returns a JWT signed with the agent's private
key. The token expires after five minutes, carries the key id in its
kidheader, and includes anyclaimsyou pass.
const token = await client.generateToken();
await fetch("https://api.example.com/v1/items", {
headers: { Authorization: `Bearer ${token}` },
});client.getCredits({ cursor?, limit? })
Reads the linked human's balance and this agent's own spending from
GET /api/v1/payments/credits on the broker.
const { credits, ledger } = await client.getCredits({ limit: 25 });
console.log(`${credits} credits available`);
for (const entry of ledger.data) {
console.log(entry.createdAt, entry.service, entry.description);
}| Field | Meaning |
|---|---|
namespace | The agent the ledger belongs to |
credits | Balance of the linked human account, in credits |
balanceAtomic | The same balance in integer units — one credit is 1,000,000 |
cashEquivalent | { amount, currency: "USD" } — the usage equivalent of the balance |
accountWide | Always true: every agent linked to the account shares the balance |
ledger.data | This agent's debits, newest first, with amounts in integer units |
ledger.pagination | { cursor, hasMore } — pass cursor back to read the next page |
limit is between 1 and 100 and defaults to 25. An agent that is not linked to
a human gets an error that tells it to run interagentic link.
Errors
Every error the SDK throws for a protocol response extends InteragenticError,
which carries code, message, statusCode and, when a person has to act,
actionUrl.
| Class | Thrown when |
|---|---|
NamespaceLockedError | The namespace is locked (423); actionUrl is the unlock page |
PaymentRequiredError | Payment is required (402); also carries amount and service |
InsufficientPermissionError | A permission or scope is missing (403); also carries missingScopes |
LinkRequiredError | A human has to link the agent or approve a credential |
import { InteragenticClient, LinkRequiredError } from "@interagentic/sdk";
try {
await new InteragenticClient().fetch("https://api.example.com/v1/items");
} catch (err) {
if (err instanceof LinkRequiredError) console.log("Open:", err.actionUrl);
else throw err;
}Everything else
The client also covers what the CLI does:
| Area | Methods |
|---|---|
| Identity | register, ensureRegistered, whoami, info, link, destroy, reset |
| Keys | client.keys.list, add, update, rotate, invalidate, delete, and client.key(id) |
| Stable API keys | createApiKey, listApiKeys, revokeApiKey |
| Organizations | listOrgs, createOrg, setActAs, createOrgInvite, redeemOrgInvite, listOrgMembers, updateMemberRole, removeOrgMember, quitOrg, deleteOrg |
| Services | fetchServiceIndex, fetchServiceAction, executeServiceAction |