The @getstackrun/sdk package is the STACK client for Node.js JavaScript and TypeScript applications. The package requires Node.js 18 or newer.
npm install @getstackrun/sdkSign in once on your development machine:
npx @getstackrun/cli auth loginimport { Stack } from '@getstackrun/sdk';
const stack = new Stack();
const agents = await stack.agents.list();new Stack() creates an API client. During local development, it can read the OAuth profile written by the CLI. In CI or production, pass the operator API key from the runtime's secret store and treat it as a full-account credential.
stack.agents.register({ name, description?, credential_access? })
stack.agents.list()
stack.agents.get(id)
stack.agents.update(id, { name?, status?, credential_access? })
stack.agents.delete(id)
stack.agents.unblock(id)stack.passports.issue({ agent_id, scopes?, ttl_seconds?, authority_binding_ids?, ... })
stack.passports.verify(token, serviceId?)
stack.passports.revoke(jti, reason?)
stack.passports.delegate({ parent_token, child_agent_id, ... })
stack.passports.refresh(token, ttlSeconds?)
stack.passports.listActive({ agentId?, sessionId? })
stack.passports.revokeAgent(agentId, reason?)
stack.passports.revokeAll(reason?)
stack.passports.checkpoint(jti, input)
stack.passports.checkout(jti, input)authority_binding_ids attaches up to eight active bindings for the exact agent and current agent key. The returned Passport carries opaque authority_refs. Authority management and the native receiver protocol use the Authority REST API.
// Publishing
stack.skills.publish({ name, description, input_schema, output_schema, ... })
stack.skills.get(id)
stack.skills.browse({ query?, tags?, trust_level? })
stack.skills.listOwned()
stack.skills.update(id, updates)
stack.skills.suspend(id)
stack.skills.activate(id)
// Invocations
stack.skills.invoke(skillId, { agent_id, input, passport_claims? })
stack.skills.getInvocation(invocationId)
stack.skills.poll(invocationId, { intervalMs?, timeoutMs? })
stack.skills.listInvocations()
// Requests
stack.skills.postRequest({ description, max_price_cents?, tags? })
stack.skills.listRequests({ status?, limit? })
stack.skills.suggestComposition(requestId)stack.identity.listProviders()
stack.identity.initiateVerification({ provider_key, return_url? })
stack.identity.completeVerification(providerKey, sessionRef)
stack.identity.listClaims()
stack.identity.revokeClaim(id)
stack.identity.replaceServiceRequirement(serviceId, requirementOrNull)
stack.identity.grantDelegation(scopes)stack.services.listAvailable()
stack.services.listConnected()
stack.services.connect({ service_id, provider, credential })
stack.services.connectCustom({ name, credential })
stack.services.disconnect(connectionId)
stack.credentials.get(provider)
stack.credentials.getByConnection(connectionId)
stack.dropoffs.create({ from_agent, to_agent, schema })
stack.dropoffs.deposit(id, agentId, payload)
stack.dropoffs.collect(id, agentId)
stack.team.invite({ email, name?, role? })
stack.team.list()
stack.team.update(id, { role?, allowed_connections? })
stack.team.revoke(id)
stack.notifications.create({ channel_type, destination, events? })
stack.notifications.list()
stack.notifications.verify(id, code)
stack.notifications.test(id)
stack.securityEvents.list({ agentId?, page?, limit? })
stack.securityEvents.resolve(id)
stack.proxy.request({ provider, method, url, headers?, body? })
stack.scan.scan({ content, context?, source? }, { passportToken? })
stack.scan.usage()
stack.audit.list({ limit?, since?, agentId?, passportJti? })
stack.audit.chainHead()
stack.audit.verifyChain({ from?, to?, limit? })// Tail recent entries — newest-first. Pass `since` (epoch ms) for
// incremental polling; pass `agentId` or `passportJti` to narrow.
const { entries, max_timestamp } = await stack.audit.list({
limit: 20,
agentId: 'agt_support',
});
// Anchor the chain head externally to prove no row was rewritten later.
const head = await stack.audit.chainHead();
console.log(head.latest_entry_hash, head.total_entries);
// Walk the chain and verify every entry's hash + link integrity.
const verdict = await stack.audit.verifyChain({ limit: 10_000 });
if (!verdict.valid) {
console.error('chain break at', verdict.first_break);
}Each entry carries layer, action,outcome, duration_ms, plus the hash-chain fields. Cascade revokes write onepassport.revoke entry plus onepassport.revoke_cascade per child — filter bypassportJti to see the chain for a single passport.
The SDK exports verifyPassportOffline as a standalone function (not a method on Stack). It verifies the JWT signature using only the public JWKS. It does not call the STACK API. Use it when a downstream service needs signature and expiry checks without an online verification call.
import { verifyPassportOffline } from '@getstackrun/sdk';
// Mode 1: JWKS URL - fetched + cached once per URL per process.
const claims = await verifyPassportOffline(token, {
jwksUrl: 'https://api.getstack.run/v1/.well-known/jwks.json',
});
// Mode 2: pre-fetched JWK - no network call at verification time.
const claims2 = await verifyPassportOffline(token, {
publicJwk: {
kty: 'OKP', crv: 'Ed25519', x: '...',
kid: 'stack-passport-v1', alg: 'EdDSA', use: 'sig',
},
});
console.log(claims.jti, claims.stk.agent_id, claims.stk.services);Offline mode checks the signature, issuer, audience, and token expiry when the token has anexp claim. Reject any result without exp. Offline verification does not check revocation or current account, agent, Mission, service, or identity state. Use POST /v1/passports/verify when current STACK state affects the decision.
Use this helper only with standard STACK-issued Passports until the SDK requires an expiry claim itself.
import { Stack, StackError, NotFoundError } from '@getstackrun/sdk';
try {
const agent = await stack.agents.get('agt_nonexistent');
} catch (err) {
if (err instanceof NotFoundError) {
console.log('Agent not found');
} else if (err instanceof StackError) {
console.log(err.code, err.status, err.message);
}
}Use the HTTP API directly when your integration needs an operation that this SDK does not expose. See /docs/api/billing for the billing shapes.
const headers = { Authorization: `Bearer ${process.env.STACK_API_KEY}` };
// Audit export (full date-range; the SDK's `stack.audit.list` covers tailing)
const exp = await fetch('https://api.getstack.run/v1/audit/export?format=ndjson', { headers });
// Billing balance
const balance = await fetch('https://api.getstack.run/v1/billing/balance', { headers }).then(r => r.json());