Reference
Types
Public models, interfaces, and enums exported from @alter-ai/alter-sdk.
Every shape on this page is exported from the package root:
import type { AlterResponse, AlterLogger, ApprovalResult, ConnectSession, RateLimitSnapshot, IdentityContext, IdentityAssertion, MemoryScope, // …} from "@alter-ai/alter-sdk";Wire format from the backend is snake_case. Exported model classes accept their documented wire shape in constructors and expose camelCase properties. Most model classes provide toJSON() in snake_case; exceptions are called out below.
AlterLogger
Section titled “AlterLogger”Pluggable logger hook. Defaults to the global console.
interface AlterLogger { warn: (message: string, ...args: unknown[]) => void; info?: (message: string, ...args: unknown[]) => void; error?: (message: string, ...args: unknown[]) => void; debug?: (message: string, ...args: unknown[]) => void;}The SDK calls warn for non-fatal diagnostics and debug when optional token-refresh retry metadata is ignored or parsed. info and error are accepted for logger compatibility but are not currently called.
AlterResponse
Section titled “AlterResponse”The return type of request().
interface AlterResponse extends Response { readonly retryInfo: RetryInfo | null;}Standard Response plus retryInfo — populated when the backend retried a token refresh; null when the token was served from cache or refreshed on the first attempt.
TokenResponse
Section titled “TokenResponse”OAuth token metadata. The plaintext access token is never exposed on this object; the SDK injects it into outgoing requests at call time.
| Field | Type | Description |
|---|---|---|
tokenType | string | Usually "Bearer". |
expiresIn | number | null | Seconds until expiry. |
expiresAt | Date | null | Absolute instant this credential stops working — the binding value: the earlier of the provider token’s own expiry and the grant’s TTL. Caching past it produces an authorization failure, not a refresh. |
tokenExpiresAt | Date | null | The provider token’s own expiry, independent of the grant’s TTL. The only clock a refresh can move. |
grantExpiresAt | Date | null | The grant’s own TTL instant (the access duration chosen at consent); null when the grant has no TTL. |
scopes | string[] | Scopes granted. |
grantId | string | Grant the token resolves to. |
providerId | string | null | Provider slug. |
scopeMismatch | boolean | The grant’s scopes no longer cover the configured required set. |
injectionHeader | string | HTTP header name used for credential injection. |
injectionFormat | string | Format string with a {token} placeholder. |
additionalCredentials | Record<string, string> | null | Non-secret metadata for multi-part authentication. Credential-bearing entries used internally are stripped before this property is exposed; null means no safe entries remain. |
additionalInjections | ReadonlyArray<{ target: string; key: string; valueSource: string }> | null | Validated multi-header or query-parameter injection rules. Runtime target values are "header" or "query_param"; the wire value_source field is exposed as valueSource. |
Helpers:
isExpired(bufferSeconds?: number): booleanneedsRefresh(bufferSeconds?: number): boolean
The two answer different questions and read different fields. isExpired() reads expiresAt — whether the credential still works. needsRefresh() reads tokenExpiresAt — whether refreshing would help.
They diverge whenever the grant’s TTL is the earlier of the two clocks: the credential is about to stop working, but a refresh cannot extend permission and the correct response is re-consent. Compare grantExpiresAt to tell which clock is binding.
RateLimitSnapshot
Section titled “RateLimitSnapshot”Frozen model exposed as lastRateLimit on App, Agent, and constrained clients.
| Field | Type | Description |
|---|---|---|
limit | number | Binding requests-per-minute ceiling for the response. |
remaining | number | Requests remaining against that binding ceiling. |
resetAt | Date | Instant when the reported window resets. |
toJSON() emits { limit, remaining, reset_at } with an ISO-8601 timestamp. The value is null until a metered response supplies the standard RateLimit-Policy / RateLimit pair or the compatibility X-RateLimit-* triple. A later unmetered response does not erase the last reading. Provider response headers are not captured because they describe the provider’s budget, not Alter’s.
RetryInfo
Section titled “RetryInfo”Metadata about retry attempts during token refresh.
| Field | Type |
|---|---|
totalAttempts | number |
successfulAttempt | number |
errors | ReadonlyArray<RetryErrorInfo> |
RetryErrorInfo
Section titled “RetryErrorInfo”One failed attempt.
| Field | Type |
|---|---|
attempt | number |
error | string |
errorType | string |
delayS | number |
permanent | boolean |
GrantInfo
Section titled “GrantInfo”A single-grant record.
| Field | Type |
|---|---|
grantId | string |
providerId | string |
scopes | string[] |
accountIdentifier | string | null — the display handle for the connected account: an email for most providers, the authorizing user’s id for Slack, the account id for Stripe, the company realmId for QuickBooks. It is what the provider surfaced for the scopes that were granted, so it can differ between connections to the same account and is not an identity key. null when the provider exposes no account identity or it could not be confirmed at connect time. |
accountDisplayName | string | null — the human-readable name for the same account (a person’s name, a workspace or company name). |
apiBaseUrl | string | null — The connection’s provider API origin when the provider serves each account from its own host: a Salesforce org’s instance URL, or https://quickbooks.api.intuit.com / https://sandbox-quickbooks.api.intuit.com for a QuickBooks production or sandbox company. Build full request URLs from it. null when the provider has one fixed API host, or the connection predates Alter recording it (reconnect to capture it). |
status | string |
scopeMismatch | boolean |
expiresAt | string | null |
createdAt | string |
lastUsedAt | string | null |
principalType | "user" | "group" | "system" | "agent" |
label | string | null |
credentialId | string | null |
grantPolicy | Record<string, unknown> | null |
UnifiedGrantListResult
Section titled “UnifiedGrantListResult”Returned by listGrants().
| Field | Type |
|---|---|
grants | GrantListItem[] |
total | number |
limit | number |
offset | number |
hasMore | boolean |
GrantListItem
Section titled “GrantListItem”Discriminated union over grantKind.
type GrantListItem = OAuthGrantItem | ManagedSecretGrantItem;OAuthGrantItem
Section titled “OAuthGrantItem”status describes permission; needsReconnect describes shared connection health. An active delegated grant retains its authority when its token needs repair. The next call attempts a refresh when possible, or raises ReAuthRequiredError for fresh consent. A reconnect flag alone does not mean the delegation is missing. Successful refresh or reconnect clears the flag.
| Field | Type |
|---|---|
grantKind | "oauth" |
grantId | string |
providerId | string |
scopes | string[] |
accountIdentifier | string | null |
accountDisplayName | string | null |
apiBaseUrl | string | null — the connection’s provider API origin (see GrantInfo.apiBaseUrl) |
status | string |
scopeMismatch | boolean |
needsReconnect | boolean |
expiresAt | string | null |
grantExpiresAt | string | null |
createdAt | string |
lastUsedAt | string | null |
principalType | "user" | "system" | "agent" |
accessVia | "ownership" | "oauth_delegation" |
delegatedAt | string | null |
delegatedAgentIds | string[] |
label | string | null |
credentialId | string | null |
grantPolicy | Record<string, unknown> | null |
parentGrantId | string | null |
depth | number |
delegable | boolean |
scopeConstraint | string[] | null |
The "agent" value on principalType marks a delegation child surfaced as its own row. parentGrantId names the grant this one was minted under (null = a root), and depth is its hop distance from the root — together they reconstruct the delegation tree from the flat list. delegable is whether the grant may be re-delegated onward; scopeConstraint is the narrowed provider-scope subset (null = inherits the parent/credential scope).
grantExpiresAt and expiresAt are two different axes: grantExpiresAt is the grant’s own TTL-policy expiry (the access duration chosen at consent; null = perpetual), while expiresAt is the underlying provider token’s expiry (auto-refreshed, never a grant terminal). status reads "expired" once grantExpiresAt has passed, even before the record is lazily flipped — so filtering on status never caches access that has actually lapsed.
ManagedSecretGrantItem
Section titled “ManagedSecretGrantItem”Returned for any managed-secret grant the caller can reach — an operator (App) list surfaces every principal kind the app owns; an agent list surfaces its own and delegated grants.
| Field | Type |
|---|---|
grantKind | "managed_secret" |
grantId | string |
managedSecretId | string |
managedSecretSlug | string |
managedSecretName | string |
agentId | string | null |
label | string | null |
status | string |
accountIdentifier | string | null |
grantPolicy | Record<string, unknown> | null |
expiresAt | string | null |
grantExpiresAt | string | null |
createdAt | string |
lastUsedAt | string | null |
principalType | "user" | "group" | "system" | "agent" |
accessVia | "ownership" | "ms_delegation" |
delegatedAt | string | null |
parentGrantId | string | null |
depth | number |
delegable | boolean |
scopeConstraint | string[] | null |
DelegationResult
Section titled “DelegationResult”Returned by agent.delegate() — the child grant minted onto another agent.
| Field | Type | Description |
|---|---|---|
grantId | string | The new child grant. |
grantKind | "oauth" | "managed_secret" | Which credential family the child belongs to. |
parentGrantId | string | The held grant the child was minted under (always set — a delegation result is always a child). |
depth | number | The child’s hop distance from the root (always >= 1). |
delegable | boolean | Whether the recipient may re-delegate this child onward. |
status | string | Grant status (e.g. "active"). |
expiresAt | string | null | Child expiry, clamped to the parent’s lifetime. |
Principal
Section titled “Principal”Discriminated union passed to createManagedSecretGrant().
type Principal = UserPrincipal | GroupPrincipal | SystemPrincipal | AgentPrincipal;PrincipalType is "user" | "group" | "system" | "agent".
NonGroupPrincipalType is "user" | "system" | "agent" and is used by OAuth
grant models, where group principals are not supported.
UserPrincipal
Section titled “UserPrincipal”| Field | Type |
|---|---|
type | "user" |
userToken | string |
label | string |
GroupPrincipal
Section titled “GroupPrincipal”| Field | Type |
|---|---|
type | "group" |
externalGroupId | string |
idpId | string |
label | string |
SystemPrincipal
Section titled “SystemPrincipal”| Field | Type |
|---|---|
type | "system" |
label? | string | null |
AgentPrincipal
Section titled “AgentPrincipal”| Field | Type |
|---|---|
type | "agent" |
label? | string | null |
CreateGrantResult
Section titled “CreateGrantResult”Returned by createManagedSecretGrant().
| Field | Type |
|---|---|
grantId | string |
principalType | "user" | "group" | "system" | "agent" |
label | string | null |
createdAt | string |
RevokeGrantResult
Section titled “RevokeGrantResult”Returned by revokeGrant().
| Field | Type |
|---|---|
success | boolean |
message | string |
grantId | string |
revokedAt | string |
GrantPolicy
Section titled “GrantPolicy”Per-grant policy.
| Field | Type |
|---|---|
expiresAt? | string | null |
createdBy? | string | null |
createdAt? | string | null |
GrantPolicyInput
Section titled “GrantPolicyInput”Camel-case policy input accepted by createConnectSession(), createConnectSessionForError(), connect(), and createManagedSecretGrant(); mintGrant() accepts the same camelCase spellings inside its wider grantPolicy object. Unknown keys throw AlterValueError; null values are omitted from the snake-case wire body.
The keyset is the union of what the individual methods accept — each row states where the field is accepted:
| Field | Type | Description |
|---|---|---|
expiresAt? | string | null | Non-empty ISO 8601 absolute expiry. Must parse as a timestamp — an unparseable string throws AlterValueError locally, before any request is sent. Accepted by createManagedSecretGrant() and mintGrant(); the Connect-session methods (createConnectSession(), createConnectSessionForError(), connect()) reject it with a 422 — expiry there is derived from the TTL the user picks on the consent screen. |
maxTtlSeconds? | number | null | Positive integer maximum TTL in seconds. Accepted by every method. |
defaultTtlSeconds? | number | null | Positive integer pre-selected TTL in seconds. The backend enforces that it does not exceed maxTtlSeconds. Accepted by the Connect-session methods and createManagedSecretGrant(); mintGrant() rejects it locally with AlterValueError — a minted grant has no TTL picker to pre-select for. |
ConnectFailedGrant
Section titled “ConnectFailedGrant”One provider the session connected but did not keep: the user did not select it on the Confirm screen, the connection could not be completed when the user confirmed it, or its selected usage limits could not be applied.
| Field | Type |
|---|---|
providerId | string |
reason | string |
message | string |
reason | Meaning |
|---|---|
not_selected | The user connected the provider but did not select it on the Confirm screen, so the connection was dropped and never became usable. |
activation_failed | The user confirmed the provider, but the connection could not be completed (for example, the same account was connected again in a newer Connect session, or the account connection was removed), so it never became usable. Connect it again. |
| any other value | The selected usage limits could not be applied (for example invalid_rule, rule_limit, storage_error), so the newly authorized grant was revoked. |
Branch on reason, never on message. Unknown reason strings are preserved.
ConnectSession
Section titled “ConnectSession”Returned by createConnectSession().
| Field | Type |
|---|---|
sessionToken | string |
connectUrl | string |
expiresIn | number |
expiresAt | string |
scopeConstraintWarnings | readonly string[] |
singleProvider | boolean |
direct | boolean |
singleProvider is true when the session names exactly one provider: the hosted UI skips the provider picker and renders no Alter-branded page. Pass it to the browser widget as open({ singleProvider }) so an inline flow opens the provider window straight from the application’s click instead of rendering a tile.
direct is true only when the application explicitly opted the session out of the end-user consent screens — the confirmation screen, the duration choice and the in-flow policy step — and the page delivers the outcome and closes. It is never implied by the provider count, and the browser widget does not consume it. A session that delegates to an agent with delegable: true reports false: the user decides onward sharing on the confirmation screen, so the screen is shown.
scopeConstraintWarnings (default []) carries one diagnostic per provider whose required scopes the requested scopeConstraint admits nothing against — the session still succeeds, but a grant minted from it would deny every call until the constraint is widened.
ManagedSecretConnectSession
Section titled “ManagedSecretConnectSession”Returned by createManagedSecretConnectSession() on App and on Agent. Same shape as ConnectSession minus scopeConstraintWarnings, plus delegableRequested: boolean.
delegableRequested echoes the delegable option the session was created with: true when the application asked the user to let the agent share the access onward, so the Connect page offers that choice when the credential’s delegation policy allows it. It is the request, not the user’s decision: the approval reports the stored setting as delegable (see createManagedSecretConnectSession()). The SDK returns the session only when the echo matches the request: delegable: true with an echo that is absent or false throws ServerFeatureUnsupportedError, and an echo of true when delegable was not sent throws BackendError.
toString() redacts connectUrl — the URL fragment carries the session token, so logging would be a leak.
ConnectResult
Section titled “ConnectResult”Returned per provider by connect() and pollConnectSession().
| Field | Type |
|---|---|
grantId | string |
providerId | string |
accountIdentifier | string | null |
scopes | string[] |
apiBaseUrl | string | null — the connection’s provider API origin (see GrantInfo.apiBaseUrl) |
operation | "creation" | "reauth" |
grantPolicy | GrantPolicy | null |
failedGrants | ConnectFailedGrant[] |
delegation | ConnectDelegation | null |
failedGrants is empty on full success. Each successful result from a partially completed multi-provider session carries the same failure list.
delegation is set when the session delegated the grant to an agent, and null otherwise.
ConnectDelegation
Section titled “ConnectDelegation”The delegation a Connect session made of one grant to its agent.
| Field | Type | Description |
|---|---|---|
agentId | string | The agent the grant was delegated to. |
delegable | boolean | The delegation’s stored onward-sharing setting after the user’s approval: whether the agent may share this access with other agents through agent.delegate(). |
policyRefused | boolean | true when the user chose to let the agent share this access but the provider’s agent sharing setting refused that choice when the connection was confirmed (the setting changed while the consent screen was open). delegable then reports the setting that was kept. false otherwise, and when the backend predates the field. |
delegable is the stored setting, not a capability. The provider’s agent sharing setting still decides each onward delegation, so a true setting is refused once the operator turns sharing off.
Parsing fails closed on a known field and ignores any other: agent_id must be a UUID string and delegable (and policy_refused, when present) a real boolean, or the poll throws BackendError with details { field: "delegation" }. A field this SDK version does not know is ignored, so a newer backend never breaks it. toJSON() returns { agent_id, delegable, policy_refused }.
AuthResult
Section titled “AuthResult”Returned by authenticate() and pollAuthSession().
| Field | Type |
|---|---|
userToken | string |
userInfo | Record<string, unknown> |
AuthSession
Section titled “AuthSession”Returned by createAuthSession(). toString() redacts authUrl (it carries the session token as the OIDC state parameter).
| Field | Type | Description |
|---|---|---|
sessionToken | string | Handle to poll with pollAuthSession(). Persistable. |
authUrl | string | IDP sign-in URL to hand to the end user. Never log it. |
expiresIn | number | Seconds until the session expires. |
expiresAt | string | ISO 8601 expiry timestamp. |
OAuthProviderCatalog
Section titled “OAuthProviderCatalog”Returned by oauthProviders.list().
| Member | Type | Description |
|---|---|---|
providers | Readonly<Record<string, OAuthProviderCatalogItem>> | Connectable providers, keyed by id ("<providerId>", …). |
getDefaultScopes(provider) | readonly string[] | Default scopes for a provider, or [] if unknown. |
getRequiredScopes(provider) | readonly string[] | Required scopes for a provider, or [] if unknown. |
OAuthProviderCatalogListOptions
Section titled “OAuthProviderCatalogListOptions”Options accepted by oauthProviders.list().
interface OAuthProviderCatalogListOptions { readonly forceRefresh?: boolean;}forceRefresh defaults to false. When true, the call bypasses the five-minute in-process cache.
OAuthProviderCatalogItem
Section titled “OAuthProviderCatalogItem”| Field | Type | Description |
|---|---|---|
id | string | Provider id. |
name | string | Internal provider name. |
displayName | string | Human-readable name. |
category | string | null | Provider category. |
description | string | null | Short description. |
logoUrl | string | null | Logo URL. |
supportsRefresh | boolean | Provider issues refresh tokens. |
supportsPkce | boolean | Provider supports PKCE. |
availableScopes | Readonly<Record<string, OAuthProviderScopeInfo>> | All requestable scopes, keyed by scope string. |
defaultScopes | readonly string[] | Scopes pre-selected in a Connect flow. |
requiredScopes | readonly string[] | Scopes that are always requested. |
status | string | Always "active" (only connectable providers are returned). |
OAuthProviderScopeInfo
Section titled “OAuthProviderScopeInfo”| Field | Type | Description |
|---|---|---|
description | string | What the scope grants. |
required | boolean | Scope is always requested. |
isDefault | boolean | Scope is pre-selected by default. |
requires | readonly string[] | Other scopes that must be selected with this scope. |
ApprovalGate
Section titled “ApprovalGate”One approver gate in an N-of-N approval group.
| Field | Type |
|---|---|
approvalId | string |
expiresAt | Date |
expiresIn | number |
approvalUrl | string |
PendingApproval
Section titled “PendingApproval”Returned by proxyRequest() when an HITL grant requires approval.
| Field | Type |
|---|---|
approvalId | string |
approvalGroupId | string |
status | "pending" |
expiresAt | Date |
expiresIn | number |
approvalUrl | string |
gates | readonly ApprovalGate[] |
Discriminate from ApprovalResult with result instanceof PendingApproval or result.status === "pending".
ApprovalGateStatus
Section titled “ApprovalGateStatus”Per-gate progress in an approval group.
| Field | Type |
|---|---|
approvalId | string |
status | ApprovalStatusValue |
expiresAt | Date |
decidedAt | Date | null |
ApprovalStatus
Section titled “ApprovalStatus”Snapshot returned by getApprovalStatus().
| Field | Type |
|---|---|
approvalId | string |
approvalGroupId | string |
status | ApprovalStatusValue |
gates | readonly ApprovalGateStatus[] |
expiresAt | Date |
decidedAt | Date | null |
decisionReason | string | null |
executedAt | Date | null |
hasResult | boolean |
executionError | string | null |
Helpers:
isTerminal: boolean—truewhen status isdenied,expired,executed, orfailed.
ApprovalStatusValue
Section titled “ApprovalStatusValue”type ApprovalStatusValue = | "pending" | "approved" | "executing" | "denied" | "expired" | "executed" | "failed";ApprovalResult
Section titled “ApprovalResult”Returned by awaitApproval() and the synchronous branch of proxyRequest().
| Field | Type |
|---|---|
approvalId | string | null |
statusCode | number |
headers | Record<string, string> |
bodyB64 | string |
bodyTruncated | boolean |
durationMs | number | null |
credentialHint | string | null |
approvalId is null for the synchronous (non-HITL) branch of proxyRequest() — there was no approval row.
durationMs is the provider round-trip duration. It is null for responses produced by workers that predate this observation. ApprovalResult.toJSON() intentionally omits this observational field.
credentialHint addresses a specific dead end. Some providers run several APIs that accept the same credential but expect it in different headers, so a perfectly valid key is rejected with 401 purely because the request went to the other API. The provider’s own error blames the key, and the natural response — rotating it — changes nothing. When the rejection matches that pattern, credentialHint says so.
It is null on success and on any rejection that does not match. It never changes statusCode or the body: the provider’s response is passed through unchanged and the hint accompanies it. Unlike durationMs it is serialized by toJSON() — it is part of the result’s meaning rather than a measurement of one attempt. A blank hint is normalized to null, so if (result.credentialHint) is the correct test for “is there an explanation”. The SDK does not reject a hint that arrives on an unexpected status — the status rule is the backend’s to enforce, and re-checking it client-side would turn a future backend addition into a hard failure in already-installed SDKs.
Helpers:
bodyBytes(): Uint8ArraybodyText(encoding?: BufferEncoding | "utf-8"): stringbodyJson(): unknown
AgentInfo
Section titled “AgentInfo”A managed agent record. Returned by app.agents.get, app.agents.update, agent.me, and others.
| Field | Type |
|---|---|
id | string |
name | string |
displayName | string | null |
type | AgentType |
status | AgentStatus |
scopes | Record<string, unknown> |
scopesPending | Record<string, unknown> | null |
scopesAppliesAt | Date | null |
policy | Record<string, unknown> |
metadata | Record<string, unknown> |
rateLimitPerMinute | number | null |
version | number |
createdAt | Date |
lastUsedAt | Date | null |
parentAgentId | string | null |
storedLegacyManagedSecretNames | readonly string[] |
storedLegacyManagedSecretNames lists the legacy display-name entries under scopes.managed_secrets that still carry authority. An update may keep these and only these; any other entry under that key is refused with a 422. Author new capabilities as slugs under scopes.managed_secret_slugs.
AgentType
Section titled “AgentType”type AgentType = "agent" | "service";AgentStatus
Section titled “AgentStatus”type AgentStatus = "active" | "inactive" | "revoked";AgentCreateResult
Section titled “AgentCreateResult”Extends AgentInfo with the freshly-minted plaintext API key.
| Field | Type |
|---|---|
apiKey | string | null |
keyId | string |
apiKey is null on an idempotency-replay — the plaintext is not server-side recoverable. Branch on result.apiKey === null rather than treating any returned value as a usable key.
AgentListResult
Section titled “AgentListResult”| Field | Type |
|---|---|
agents | AgentInfo[] |
total | number |
limit | number |
offset | number |
hasMore | boolean |
AgentKey
Section titled “AgentKey”A single API key bound to a managed agent.
| Field | Type |
|---|---|
keyId | string |
keyPrefix | string |
name | string |
createdAt | Date |
deprecatedAt | Date | null |
revokedAt | Date | null |
lastUsedAt | Date | null |
Computed property:
status: AgentKeyStatus—"revoked"whenrevokedAtis set,"deprecated"whendeprecatedAtis set,"active"otherwise.
AgentKeyStatus
Section titled “AgentKeyStatus”type AgentKeyStatus = "active" | "deprecated" | "revoked";AgentKeyMintResult
Section titled “AgentKeyMintResult”Extends AgentKey with the plaintext apiKey (returned exactly once).
| Field | Type |
|---|---|
apiKey | string | null |
AgentKeyList
Section titled “AgentKeyList”class AgentKeyList { readonly items: AgentKey[] }APIKeyInfo
Section titled “APIKeyInfo”A scoped API key (not bound to a managed agent).
| Field | Type |
|---|---|
id | string |
name | string |
keyPrefix | string |
keyType | "rk" | "ak" | "dk" | "pk" |
scopes | readonly string[] |
scopeVersion | number |
cidrAllowlist | readonly string[] | null |
rateLimitRpm | number | null |
effectiveRateLimitRpm | number | null |
rateLimitSource | "key" | "organization" | "platform_default" | null |
expiresAt | string | null |
deprecatedAt | string | null |
revokedAt | string | null |
parentKeyId | string | null |
createdAt | string |
lastUsedAt | string | null |
status | "active" | "rotated" | "revoked" |
rateLimitRpm is the per-key override chosen at mint time; null means no override, not unlimited. effectiveRateLimitRpm is the requests-per-minute ceiling actually enforced for the key once the organization ceiling and the platform default are applied, and rateLimitSource names which of those produced it. Throttling decisions should read effectiveRateLimitRpm. Both are optional on parse: a backend that does not report them leaves each null, which means not reported — never unlimited. A live backend always sends both.
MintedKey
Section titled “MintedKey”Extends APIKeyInfo with the plaintext.
| Field | Type |
|---|---|
apiKey | string |
ScopeCatalog
Section titled “ScopeCatalog”Returned by scopes.list().
| Field | Type |
|---|---|
scopeVersion | number |
resources | Readonly<Record<string, ResourceScopes>> |
actionVerbs | readonly string[] |
deprecated | readonly string[] |
ResourceScopes
Section titled “ResourceScopes”interface ResourceScopes { readonly verbs: readonly string[];}RequestRule
Section titled “RequestRule”A request rule passed to withConstraints({ rule }) — cryptographically
bound to every request the constrained client makes and enforced on
credential-using calls.
interface RequestRule { ruleType: string; ruleBody: Record<string, unknown>;}Content-match rule types
Section titled “Content-match rule types”Inputs to contentMatchRule(options), which returns a RequestRule.
type ContentParamOp = | "equals" | "any_in" | "not_subset_of" | "gt" | "gte" | "lt" | "lte" | "outside_windows";
type ContentMatchEffect = "deny" | "redact" | "step_up";
type ContentMatchFamily = | "send" | "read" | "write" | "delete" | "admin" | "payment";
interface ContentParamCondition { name: string; op: ContentParamOp; value: string | number | readonly string[] | TimeWindows;}
/** The `outside_windows` operand: 1–20 windows in an IANA timezone. */interface TimeWindows { windows: readonly TimeWindow[]; timezone: string;}
interface TimeWindow { days: readonly string[]; // unique "mon" … "sun" start: string; // "HH:MM" end: string; // "HH:MM" or "24:00"; earlier than start = overnight}
interface ContentMatchRuleOptions { operations?: readonly string[]; families?: readonly ContentMatchFamily[]; params?: readonly ContentParamCondition[]; effect?: ContentMatchEffect; redactFields?: readonly string[]; maxSessionAgeSeconds?: number;}At least one of operations or families is required. effect defaults to "deny". outside_windows fires when a time-range parameter (a calendar event’s event_time) is not wholly inside the windows; back-to-back occurrences count as one stretch of time. redactFields is required only for "redact"; maxSessionAgeSeconds is required only for "step_up" and must be an integer in [1, 86400].
String comparisons in params conditions are normalized: equals and the any_in/not_subset_of pattern matching compare case-insensitively with surrounding whitespace trimmed (internal whitespace is significant) — deliberate anti-bypass semantics, so a condition cannot be dodged by a case or padding variant. Number-typed parameters compare numerically (a string-typed parameter compares as normalized text). On a set-shaped parameter (for example recipients), equals matches only an exact single value — a multi-member set never matches; use any_in to match a member.
UserSpan
Section titled “UserSpan”Input to client.spans.emit().
| Field | Type |
|---|---|
traceId | string |
name | string |
startTime | Date | string |
spanId? | string |
parentSpanId? | string |
endTime? | Date | string |
attributes? | Readonly<Record<string, string>> |
MAX_SPANS_PER_BATCH is the exported batch cap (50). spans.emit() accepts from 1 through MAX_SPANS_PER_BATCH items.
EmitSpansResult
Section titled “EmitSpansResult”Returned by client.spans.emit().
| Field | Type |
|---|---|
accepted | number |
APICallAuditLog
Section titled “APICallAuditLog”Audit payload model used by retrieve-mode provider-call reporting.
| Field | Type |
|---|---|
grantId | string |
tokenGeneration | string | null |
providerId | string |
method | string |
url | string |
requestHeaders | Record<string, string> | null |
requestBody | unknown |
responseStatus | number |
responseHeaders | Record<string, string> | null |
responseBody | unknown |
latencyMs | number |
timestamp | Date |
reason | string | null |
context | Record<string, string> | null |
sanitize() returns the snake_case submission shape after filtering sensitive headers. This class exposes sanitize() rather than toJSON().
Identity
Section titled “Identity”IdentityContext
Section titled “IdentityContext”Returned by app.resolveIdentity() and agent.resolveIdentity(). The canonical identity set the platform resolved for the request — key external data (memory partitions, channel sessions, authorization tuples) on these IDs, never on email or a raw IDP sub.
| Field | Type | Description |
|---|---|---|
appId | string | The calling application (tenant). |
appUserId | string | null | Canonical end-user key. null for headless calls. |
externalSubjectId | string | null | Stable external join key — the IDP subject identifier. |
idpId | string | null | Identity provider the subject belongs to. |
userStatus | string | null | "active" | "suspended". Deprovisioned users are rejected at resolution, never returned. |
groupIds | readonly string[] | Stable external group IDs of the user’s unrevoked memberships. |
agentId | string | null | Canonical agent key. null for plain app callers. |
actorId | string | null | Audit correlation label only — NOT a partition key. |
trace | IdentityTrace | null | Echo of the ambient run/thread trace context. |
email | string | null | Only with includeProfile: true. |
displayName | string | null | Only with includeProfile: true. |
Method memoryScope(options?: { agentOnly?: boolean }): MemoryScope derives the private partition for an identity that carries local provenance (an authenticated SDK response or a verified assertion). It throws AlterValueError when options is not an object or agentOnly is not a boolean, and MemoryIsolationError (memory_identity_unverified, memory_identity_expired, memory_agent_required, memory_user_required, memory_user_not_active or memory_user_cannot_be_dropped) for an unverified or ineligible context. See Private memory and Propagate identity into memory layers.
IdentityTrace
Section titled “IdentityTrace”| Field | Type |
|---|---|
runId | string | null |
threadId | string | null |
MemoryScope
Section titled “MemoryScope”Derived only from an authenticated SDK identity response or verified assertion. memoryScope({ agentOnly: false }) requires an active user and authenticated agent; explicit agentOnly: true requires a headless agent. Untrusted or ineligible contexts throw MemoryIsolationError.
| Field | Type | Description |
|---|---|---|
namespace | readonly string[] | Versioned private application + agent + user partition; explicit headless partitions use a distinct kind. Identifiers are UTF-8 base64url encoded. |
partitionKey | string | Namespace joined by /, with a trailing /. |
userKey | string | null | alter:user:<appUserId>; null for a headless (agent-only) scope. Correlation metadata, not a partition. |
agentKey | string | alter:agent:<agentId>; always set, because a scope requires an authenticated agent. Correlation metadata, not a partition. |
appKey | string | alter:app:<appId>; always set. Correlation metadata, not a partition. |
namespaceFor(path: readonly string[] = []): readonly string[] appends encoded developer subdivisions and throws AlterValueError for a path that is not an array of non-empty, valid-Unicode strings, has more than 16 segments, or has a segment longer than 255 UTF-8 bytes. toJSON() serializes the fields above as snake_case. Serialized scope metadata is not authorization. Use ScopedMemoryStore for live enforcement, or verifyIdentityAssertion with an assertion-backed store for bounded offline access. See the complete integration and migration guide.
IdentityAssertion
Section titled “IdentityAssertion”Returned by app.assertIdentity() and agent.assertIdentity().
| Field | Type | Description |
|---|---|---|
token | string | Compact ES256 JWS — verify against the published Alter identity JWKS. Redacted from toString() / inspect output. |
expiresAt | Date | Absolute expiry (short TTL by design — default 120s, bounds 10–300s). |
identity | IdentityContext | The identity the assertion encodes. |
The assertion is identity-only: it carries no provider tokens, no credentials, no raw IDP claims, and grants nothing by itself — downstream systems map it to their own authorization.
Private memory
Section titled “Private memory”Version compatibility:
ScopedMemoryStore,NamespaceStore,MemoryItem,JsonWebKeySet,verifyIdentityAssertionandMemoryIsolationError.codeare unreleased: they ship in the next@alter-ai/alter-sdkrelease after 0.27.0, which does not export them.
Run these in the trusted application; keep the raw store and its credentials out of agent tools. Every method throws AlterValueError for a malformed argument and MemoryIsolationError (branch on code; see Errors) for an authorization outcome.
ScopedMemoryStore
Section titled “ScopedMemoryStore”new ScopedMemoryStore( store: NamespaceStore, identity: IdentityContext, options?: ScopedMemoryStoreOptions,)Binds every exposed store operation to one verified private identity. identity must carry local provenance (an authenticated response or a verified assertion). With refreshIdentity, the resolver is awaited at the start of every operation and must call Alter each time: the store proves the returned identity was minted after the operation started (memory_refresh_not_live otherwise) and that it still resolves to the same partition (memory_identity_changed otherwise). Without a resolver, identity must be assertion-backed and unexpired (memory_live_refresh_required for a resolved snapshot). The constructor throws AlterValueError when options is not an object or refreshIdentity is not a function, plus the memoryScope() outcomes above.
| Member | Signature | Notes |
|---|---|---|
scope | get scope(): MemoryScope | Partition metadata, never an authorization capability. |
get | get(path: readonly string[], key: string): Promise<MemoryItem | null> | The result must come back inside the exact namespace with the same key, else memory_store_scope_violation. |
put | put(path: readonly string[], key: string, value: Record<string, unknown>): Promise<void> | value must be a plain object. |
delete | delete(path: readonly string[], key: string): Promise<void> | |
search | search(path?: readonly string[], options?: MemorySearchOptions): Promise<MemoryItem[]> | limit defaults to 10, offset to 0. Every result must sit under the requested namespace. |
listNamespaces | listNamespaces(path?: readonly string[], options?: { limit?: number; offset?: number }): Promise<string[][]> | limit defaults to 100, offset to 0. Every result must sit under the requested namespace. |
path is a developer-owned subdivision appended under the verified partition (at most 16 segments of at most 255 UTF-8 bytes each). key is a non-empty string of at most 512 characters. limit must be a positive safe integer and offset a non-negative safe integer. A resolver error propagates unchanged; there is no offline fallback.
ScopedMemoryStoreOptions
Section titled “ScopedMemoryStoreOptions”| Field | Type | Description |
|---|---|---|
refreshIdentity | () => Promise<IdentityContext> | Optional. Must perform authenticated resolution on every invocation, without caching. |
agentOnly | boolean | Optional, default false. Derive the headless application + agent partition. |
NamespaceStore
Section titled “NamespaceStore”The structural namespace-store interface a wrapped store must satisfy, implemented by LangGraph’s BaseStore (InMemoryStore included): get(namespace, key), put(namespace, key, value), delete(namespace, key), search(namespacePrefix, options?) and listNamespaces({ prefix?, limit?, offset? }), with namespaces as string[]. It deliberately exposes no raw batch operation.
MemoryItem
Section titled “MemoryItem”interface MemoryItem { namespace: string[]; key: string; value: Record<string, unknown>;}MemorySearchOptions
Section titled “MemorySearchOptions”| Field | Type | Description |
|---|---|---|
query | string | Optional free-text query passed to the store. |
filter | Record<string, unknown> | Optional structured filter passed to the store. |
limit | number | Default 10. |
offset | number | Default 0. |
JsonWebKeySet
Section titled “JsonWebKeySet”{ readonly keys: readonly JsonWebKey[] }: the JWK Set document fetched from the configured issuer (RFC 7517). JsonWebKey declares only the parameters the verifier inspects (kid, kty, crv, alg, use, key_ops, x, y); a parsed JWKS response and a jose key set are both assignable.
VerifyIdentityAssertionOptions
Section titled “VerifyIdentityAssertionOptions”| Field | Type | Description |
|---|---|---|
issuer | string | The exact issuer value to pin (no trailing slash). |
audience | string | The audience the assertion was minted for. |
jwks | JsonWebKeySet | Trusted keys fetched from the configured issuer. |
expectedAppId | string | The application the assertion must be bound to. |
expectedAgentId | string | Optional. When set, the acting agent must match. |
verifyIdentityAssertion
Section titled “verifyIdentityAssertion”verifyIdentityAssertion( token: string, options: VerifyIdentityAssertionOptions,): Promise<IdentityContext>Asynchronous (the verifier uses WebCrypto; the Python twin is synchronous by design). Verifies an Alter ES256 assertion against configured trust anchors only; token-supplied key URLs are never fetched. Pins ES256 and typ, selects the key by kid (a key set member carrying the private d parameter is rejected), checks issuer, audience, signature and the required claims, keeps exp strict with a 5-second leeway on iat only, enforces the 300-second lifetime ceiling, binds the application (and the agent when expectedAgentId is given), and requires agent_auth to be present whenever an actor is asserted without pinning its value. Returns a trusted IdentityContext (application, current agent, represented user, active-at-issuance status) that memoryScope() and ScopedMemoryStore accept until the signed expiry. Throws AlterValueError for a missing or malformed option and MemoryIsolationError with code === "memory_assertion_invalid" and a coarse details.reason (malformed, header, key, signature, lifetime, claims or binding) for a rejected token.
Provider specification models
Section titled “Provider specification models”ProviderSpecKind
Section titled “ProviderSpecKind”type ProviderSpecKind = "oauth" | "managed";This union validates and types the kind argument on providerSpecs methods. ProviderSpec.providerKind remains a broader string to match the Python SDK’s wire model, so a newly introduced backend value does not fail in TypeScript while the Python model accepts it.
ProviderSpec
Section titled “ProviderSpec”| Field | Type |
|---|---|
providerKind | string |
providerId | string |
version | number |
provenance | string |
sourceUrl | string | null |
contentHash | string |
operationCount | number |
fetchedAt | Date |
changedAt | Date |
title | string | null |
specVersion | string | null |
SpecOperationsListOptions
Section titled “SpecOperationsListOptions”Options accepted by providerSpecs.listOperations().
| Field | Type | Default | Description |
|---|---|---|---|
search? | string | — | Case-insensitive substring filter over operation id, path, and summary. Non-empty and at most 200 characters when supplied. |
limit? | number | 100 | Page size from 1 through 500. |
offset? | number | 0 | Non-negative page offset. |
SpecOperation
Section titled “SpecOperation”| Field | Type |
|---|---|
operationId | string |
method | string |
pathTemplate | string |
summary | string | null |
SpecOperationsPage
Section titled “SpecOperationsPage”| Field | Type |
|---|---|
items | readonly SpecOperation[] |
total | number |
limit | number |
offset | number |
hasMore | boolean |
spec | ProviderSpec |
SpecOperationDetail
Section titled “SpecOperationDetail”| Field | Type |
|---|---|
operationId | string |
method | string |
pathTemplate | string |
summary | string | null |
paramsSchema | Record<string, unknown>[] | null |
requestSchema | Record<string, unknown> | null |
responseSchema | Record<string, unknown> | null |
spec | ProviderSpec |
HttpMethod
Section titled “HttpMethod”enum HttpMethod { GET = "GET", POST = "POST", PUT = "PUT", PATCH = "PATCH", DELETE = "DELETE", HEAD = "HEAD", OPTIONS = "OPTIONS",}CallerType
Section titled “CallerType”enum CallerType { SERVICE = "service", AGENT = "agent",}Distinguishes backend services from AI agents at the audit layer. Set via the callerType constructor option.
Provider
Section titled “Provider”Slug enum for the OAuth provider catalog. Plain provider-ID strings are also accepted by request() and createConnectSession(); the enum provides IDE autocomplete.