Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.alterauth.com/llms.txt

Use this file to discover all available pages before exploring further.

The TypeScript SDK ships as the @alter-ai/alter-sdk package on npm. Node 20+. Server-side; for browser-side OAuth popups, see the Connect SDK.
npm install @alter-ai/alter-sdk
For end-to-end walkthroughs, see the Quickstart and Guides. This page is API reference only.

Clients

Two classes.

App

The application-side client. Construct with an alter_key_app_… API key.
import { App, CallerType } from "@alter-ai/alter-sdk";

const app = new App({
  apiKey: string,
  timeout?: number,                        // ms, default 30000
  caller?: string,
  callerType?: CallerType,                 // default SERVICE
  userTokenGetter?: () => string | Promise<string>,
  logger?: AlterLogger,
});
OptionTypeDefault
apiKeystring
timeoutnumber (ms)30000
callerstring
callerTypeCallerType | "agent" | "service"SERVICE
userTokenGetter() => string | Promise<string>
loggerAlterLogger
Resources are released with await app.close(). The SDK does not auto-close on process exit.

Agent

The workload-side client. Construct with an alter_key_agent_… key (or via app.getAgent(agentId) for the impersonation path).
import { Agent } from "@alter-ai/alter-sdk";

const agent = new Agent({
  apiKey: string,
  timeout?: number,
  caller?: string,
  userTokenGetter?: () => string | Promise<string>,
  logger?: AlterLogger,
});
Agent exposes a strict subset of App — methods that don’t apply to an agent principal are absent (TypeScript flags the missing methods at compile time).

Making requests

request and proxyRequest are the two runtime modes. They share the same option shape; the difference is where the third-party call happens and what the SDK returns.
request (retrieve)proxyRequest (proxy)
Token returned to SDKYes — to the SDK processNo — stays on the backend
Third-party call made byThe SDKThe Alter backend
Return typePromise<AlterResponse>Promise<ApprovalResult | PendingApproval>
Scope required on the API keytokens:retrieveproxy:execute
HITL grantsRejected (hitl_grant_requires_proxy)Required path
A non-HITL grant works in either mode. Pick proxy when wire-level audit, strong token isolation, or backend-side policy enforcement matter; pick retrieve for long-lived clients, streaming, or any path where the extra hop hurts. See the runtime modes page for the full tradeoffs.

request(method, url, options?) -> Promise<AlterResponse>

Retrieve-mode call. The SDK fetches a token from the backend, injects it into the outgoing provider request, and makes the call itself.
const response = await app.request(
  HttpMethod.GET,
  "https://www.googleapis.com/calendar/v3/calendars/primary/events",
  {
    provider: "google",
    queryParams: { maxResults: "10" },
    reason: "Sync events on page load",
  },
);
AlterResponse extends the standard Response; response.retryInfo exposes refresh-retry metadata when applicable. Options:
OptionDescription
grantIdExplicit grant.
providerResolve from userTokenGetter.
jsonRequest JSON body.
headersExtra request headers.
queryParamsQuery-string parameters.
reasonAudit reason.
contextApplication metadata (Record<string, string>).
userTokenPer-call JWT override.
accountDisambiguator for ambiguous JWT resolution.

proxyRequest(method, url, options?) -> Promise<ApprovalResult | PendingApproval>

Proxy-mode call. The backend holds the token, makes the outgoing call, and returns the result — application code and the SDK never observe the token. Use proxy mode whenever you want the backend to be the credential boundary, regardless of whether HITL is configured. For grants with HITL configured, this is the only path that works: the backend gates the call on the approval decision and only then executes. Options:
OptionDescription
grantIdExplicit grant.
providerResolve from userTokenGetter.
jsonRequest JSON body.
headersExtra request headers (Authorization is auto-injected on the backend).
queryParamsQuery-string parameters.
reasonAudit reason — also shown to the approver when HITL is configured.
contextApplication metadata (Record<string, string>).
userTokenPer-call JWT override.
accountDisambiguator for ambiguous JWT resolution.
Returns:
  • ApprovalResult — the call ran synchronously (no approval required, or approval was pre-granted). Contains the third-party response.
  • PendingApproval — an approver must act before the call executes. Poll with getApprovalStatus(approvalId) or block with awaitApproval(approvalId, { timeout }). See the HITL guide.
Branch on the return type to handle both cases:
const result = await app.proxyRequest(
  HttpMethod.POST,
  "https://api.example.com/transfer",
  {
    grantId,
    json: { amount: 1000 },
    reason: "Quarterly payout",
  },
);
if (result.kind === "pending") {
  // surface to the user, wait for approval, then poll
} else {
  // ran synchronously; result.response is the provider response
}

boto3Client(grantId, service, region?)

Returns an AWS SDK client signed with credentials from an AWS managed-secret grant.

Grants

listGrants(options?) -> Promise<UnifiedGrantListResult>

Paginated. Each item is either OAuthGrantItem or ManagedSecretGrantItem, discriminated on grantKind.

revokeGrant(grantId, options?) -> Promise<RevokeGrantResult>

App-only.

createManagedSecretGrant(managedSecretId, options) -> Promise<CreateGrantResult>

options.principal is one of UserPrincipal, GroupPrincipal, SystemPrincipal, AgentPrincipal.

revokeDelegation(grantId, agentId?)

App: revokeDelegation(grantId, agentId). Agent: revokeDelegation(grantId).

Connect flow

  • createConnectSession(options) -> Promise<ConnectSession>
  • createManagedSecretConnectSession(options) -> Promise<ManagedSecretConnectSession>
  • connect(options) -> Promise<ConnectResult[]> — headless flow.

Authentication helpers (App only)

  • authenticate(options?) -> Promise<AuthResult>
  • verifyUserToken(token) -> Promise<string | null>

Approvals

  • getApprovalStatus(approvalId) -> Promise<ApprovalStatus>
  • awaitApproval(approvalId, options?) -> Promise<ApprovalResult>

Managed agents (App only)

app.agents:
  • create(options) -> Promise<AgentCreateResult> — plaintext key returned once.
  • list(options?) -> Promise<AgentListResult>
  • get(agentId) -> Promise<AgentInfo>
  • getByName(name) -> Promise<AgentInfo | null>
  • update(agentId, options) -> Promise<AgentInfo>
  • mintKey(agentId) -> Promise<AgentKeyMintResult>
  • listKeys(agentId) -> Promise<AgentKeyList>
  • deprecateKey(agentId, keyId), undeprecateKey(...), revokeKey(agentId, keyId, { force?: boolean })

Scoped key derivation

app.keys / agent.keys:
  • derive({ scopes, expiresIn, cidrAllowlist?, rateLimitRpm? }) -> Promise<MintedKey>
  • rotate(keyId) -> Promise<MintedKey>
  • revoke(keyId) -> Promise<APIKeyInfo>

Scope catalog

  • app.scopes.getCatalog() -> Promise<ScopeCatalog>

Attenuation

  • app.withConstraints({ scopes }) -> App — narrow-only sibling instance. See Scopes.

Agent introspection (Agent only)

  • agent.me() -> Promise<AgentInfo>
  • (trace API for nested-call audit scoping lands in a follow-up TS release; today the Python SDK is the recommended path for multi-step agents.)

Models

Public types exported from @alter-ai/alter-sdk:
TypePurpose
TokenResponseOAuth token metadata.
GrantInfoSingle-grant record.
OAuthGrantItem, ManagedSecretGrantItem, GrantListItem, UnifiedGrantListResultDiscriminated-union grant types.
ConnectSession, ManagedSecretConnectSession, ConnectResult, AuthResultConnect / auth results.
Principal (UserPrincipal, GroupPrincipal, SystemPrincipal, AgentPrincipal)Managed-secret grant principal.
GrantPolicyTTL and policy fields.
PendingApproval, ApprovalStatus, ApprovalResultHITL flow.
AgentInfo, AgentCreateResult, AgentListResultManaged agents.
AgentKey, AgentKeyMintResult, AgentKeyList, AgentType, AgentStatus, AgentKeyStatusPer-agent keys.
APIKeyInfo, MintedKeyDerived API keys.
ScopeCatalog, ResourceScopesScope catalog.
RetryInfo, RetryErrorInfoRetry metadata.
AlterResponseThe Response subtype returned by request().
All wire-shape responses use snake_case JSON; the SDK constructors accept snake_case input and expose camelCase getters.

Errors

See Errors for the full hierarchy. The classes exported from @alter-ai/alter-sdk: AlterSDKError, AlterValueError, BackendError, ReAuthRequiredError, GrantExpiredError, GrantRevokedError, CredentialRevokedError, GrantDeletedError, GrantNotFoundError, AmbiguousGrantError, PolicyViolationError, InsufficientScopeError, TokenRefreshInProgressError, NoDelegatedGrantError, ConnectFlowError, ConnectDeniedError, ConnectConfigError, ConnectTimeoutError, ProviderAPIError, ScopeReauthRequiredError, NetworkError, TimeoutError, ApprovalError, ApprovalDeniedError, ApprovalExpiredError, ApprovalTimeoutError, ApprovalExecutionFailedError, AgentError, InvalidKeyError, AgentNotFoundError, AgentNameExistsError, MeRequiresAgentKeyError, KeyRevokedError, AgentInactiveError, AgentRevokedError, IdempotencyKeyBodyMismatchError, IdempotencyKeyAgentRevokedError, IdempotencyKeyAgentInactiveError, AgentCannotMintSubagentsError, AgentScopeNarrowingNotSupportedError, KeyAlreadyRevokedError, KeyNotFoundError, LastActiveKeyError.

Enums

EnumMembers
HttpMethodGET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
CallerTypeSERVICE, AGENT
ProviderSlug enum for the OAuth provider catalog.

Express recipe

import express from "express";
import { AsyncLocalStorage } from "node:async_hooks";
import { App, HttpMethod } from "@alter-ai/alter-sdk";

const jwt = new AsyncLocalStorage<string>();
const alter = new App({
  apiKey: process.env.ALTER_API_KEY!,
  userTokenGetter: () => jwt.getStore()!,
});

const app = express();

app.get("/api/events", authenticated, async (req, res, next) => {
  try {
    await jwt.run(req.user.jwt, async () => {
      const r = await alter.request(
        HttpMethod.GET,
        "https://www.googleapis.com/calendar/v3/calendars/primary/events",
        { provider: "google" },
      );
      res.json(await r.json());
    });
  } catch (e) { next(e); }
});