Topolo Docs Topolo Platform
Open workspace

SDK package

Use @topolo/sdk 0.23.22 with exact discovery, authorization, recovery and runtime boundaries.

Use @topolo/sdk to call Topolo APIs from an application or integration that already has a Topolo credential. Use @topolo/login for the OAuth or OIDC login integration itself. This handbook describes the published 0.23.22 package as a versioned reference dated 15 October 2026. It covers this exact released version; verify an installed consumer separately. [S1]

Set up an integration

Use Node.js 20 or newer. Pin the package when reproducing this version:

npm install @topolo/sdk@0.23.22

The root export provides the API client; @topolo/sdk/node provides Node credential-store helpers. The package exposes ESM and CommonJS entries and TypeScript declarations. Normal API integrations can use the root export without directly operating the saved credential store. [S2]

The following initialization example is illustrative and unexecuted. Supply an already authorized credential through an approved secret source. Never put its value in source control, examples, or diagnostic output.

import { createTopolo } from '@topolo/sdk';

const topolo = createTopolo({
  credential: { kind: 'api_key', apiKey: process.env.TOPOLO_API_KEY! },
  agent: {
    clientName: 'example-integration',
    clientVersion: '1.0.0',
    agentName: 'example-service',
  },
});

const identity = await topolo.identity.whoami();

Check the returned identity and organization before selecting a task. Ordinary action operations derive organization context from the credential. Changing a browser's organization does not retarget an issued credential. Use a separately authorized credential for a different context; do not add a guessed organization override to an action request. [S1, S3]

Discover an application and its actions

Search the live catalog available to the credential. It determines which applications and actions can be used; a package's built-in knowledge is not an authorization list. searchServices and searchActions return a page with nextCursor and hasMore. Retain the cursor when continuing the same search. The older listServices and listActions convenience methods are deprecated in the shipped declarations. [S3]

This illustrative discovery sequence uses values obtained from earlier catalog results:

const services = await topolo.client.searchServices({ query: 'mail', limit: 25 });
// Select application from services.services; do not invent its ID.
const application = '<application returned by discovery>';
const actions = await topolo.client.searchActions({ service: application, limit: 25 });
// Select an exact actionId from actions.actions.
const actionId = '<actionId returned by discovery>';
const action = await topolo.client.getAction(actionId);
const resources = await topolo.client.listBindableResources(application);

Inspect the action's input and output schemas, authorization mode, required permissions, effects, examples, resource metadata, verification steps, and recovery contract. A runtime-authorized action may be discoverable while execution is refused for the concrete request. An example marked requiresDiscovery is not an empty request ready to run. Resolve its identifiers first. [S1, S3]

Prepare a request with the correct resource

The resource is separate from the organization credential and from the action's own JSON input. Use the published bindable resource catalog to obtain its type and identifier. When resource context is needed, provide both resourceType and resourceId.

// Illustrative template. Replace these with discovered, schema-valid values.
const input = {}; // Valid only if the selected action's schema permits it.
const resource = {
  resourceType: '<published resource type>',
  resourceId: '<discovered resource ID>',
};
const preparation = await topolo.client.prepareAction(actionId, input, { resource });

Read preparation.missingFields and preparation.plan. The plan describes validation, confirmation requirements, the resolved request, verification instructions, and any rollback action ID. Fix missing or invalid input before proceeding. Planning does not perform the requested business action. [S3]

Execute only the approved operation

Use readAction for a published automatic read. Use callAction for an authorized action, keeping the same exact input and resource context. Mutating HTTP requests are gated by confirm: true; that flag records transport confirmation and does not grant permission or replace the task owner's authorization. Keep the default write-confirmation guard enabled. [S1, S3]

For an already authorized mutation, include confirmation when preparing the exact plan. Execute only when the plan's validation and execution conditions are satisfied. After execution, follow the action's published verification steps and read the actual target record or version. Do not equate a returned request with a delivered business outcome.

Uploads are also contract-driven: uploadAction requires the action to publish an upload profile, accepted MIME patterns, and a byte limit. Follow its inline-base64 or URL-session mapping rather than inventing upload endpoints. Use the generic request method only when the exact service, method, path, input, and verification behavior are documented. [S1]

Handle reauthorization and rate limits

SDK 0.23.22 exports TopoloRateLimitError, TopoloReauthRequiredError, and topoloRetryAfterSeconds. Check the structured error code and supported fields; do not dump a raw credential response into a log. [S3, S4]

ResultMeaning and supported handling
reauth_requiredThe saved sign-in needs authorization. Inspect error.reauthorization for its environment, context, state, verification URL, user code, expiry, polling interval, and equivalent login command. Present the human approval instructions for that exact context. The prompt excludes the device code.
TopoloRateLimitErrorThe SDK class marks the error retryable: true and supplies retryAfter and, when parseable, retryAfterSeconds. Respect the service contract and the approved task boundary; that flag alone does not prove an arbitrary business mutation had no effect.
TopoloPermissionErrorInspect .required and the selected resource. Respect the denial rather than widening access automatically.
TopoloAuthError or another TopoloHttpErrorPreserve the code, status, sanitized request ID and structured details. Follow the credential owner's or selected action's recovery contract.

topoloRetryAfterSeconds accepts a delta-seconds value or an HTTP-date value. For service HTTP 429 responses, the request implementation automatically retries only GET and HEAD, with at most two rate-limit retries when the calculated wait is no more than ten seconds. Without a retry header, its two backoff delays default to one and two seconds. A longer or invalid wait leaves the error to the caller. A transport failure on a GET has a separate single retry. [S3, S4]

The 429 backoff loop is not a mutation replay policy. Authentication refresh and any resulting request resubmission follow a separate path. Preserve an uncertain write outcome and use the action's verification or reconciliation contract before another write. A retry interval controls pacing, not authority to override a pause or change credentials.

Use the Node saved sign-in helpers deliberately

The @topolo/sdk/node entry owns saved-profile renewal and configuration writes. Those operations can contact Auth and change local sign-in state even when the eventual business request is a read. Use them only for a profile the application is authorized to manage. [S1, S5]

In 0.23.22, writeConfig uses the same cooperative configuration lock as renewal. Renewal re-reads the current store while holding that lock, shares an exchange within a process, and uses atomic temporary-file replacement. Retired refresh-token fingerprints help prevent a stale cooperating writer from restoring a rotated or refused token. This does not fence arbitrary filesystem writers or older SDKs outside the protocol. The default lock wait is fifteen seconds; the built-in OAuth exchange transport has a ten-second timeout. A timeout is not evidence that a remote exchange had no effect. [S1, S5]

An Auth invalid_grant or expired_token refusal recognized as terminal ends renewal of that saved grant. The helper records reauthorization for its environment and context and can start or reuse a shared device-approval flow. A transient renewal failure, including an Auth 429, retains the saved grant rather than treating it as terminal. Approval for a different organization is reported as a mismatch and stored under its own context; it does not silently retarget the original request. [S5]

The public Node declarations provide these distinct interfaces:

  • readReauthorization(environment, key?) reads status. The implementation redacts the pending device code; do not substitute a raw configuration-file read.
  • continueReauthorization(environment, key) advances the shared flow when its interval permits. It can start or poll Auth and write the store; it is not a diagnostic dry run.
  • awaitReauthorization(environment, key, options) waits interactively with a timeout, optional abort signal, and onPrompt callback. It does not grant approval itself.

Display only the documented approval prompt fields. Do not extract refresh tokens, device codes, or lock markers, delete a lock, or use these helpers as an unapproved repair of another managed profile. [S5]

Pass protected action results without exposing them

With a protected action-secret store configured, returned credentials can be opaque references; without that store they are redacted. Pass a reference unchanged into the next approved published action. Do not turn it into plaintext or infer upstream revocation from local reference cleanup. [S1, S3]

Sources for this version

[S1] Published SDK 0.23.22 archive, member package/README.md.

[S2] The same archive, member package/package.json.

[S3] The same archive, member package/dist/index.d.ts.

[S4] The same archive, member package/dist/index.js, especially TopoloRateLimitError and the request retry paths.

[S5] The same archive, members package/dist/node/credential-store.d.ts and package/dist/node/credential-store.js. Examples are illustrative and unexecuted; no response capture is supplied.