TypeScript client

Discover and execute versioned tools from a server-side application.

The TypeScript client lives in packages/sdk as @arc0/sdk. This source package is available in the workspace; an npm release is not yet published. For a standalone app, install a locally packed 0.2.0 tarball. After publication use npm install @arc0/sdk. The package ships compiled ESM and TypeScript declarations for Node.js 22 or later. Keep API keys on your server. Use a self-bound key for a single person, or set endUserId explicitly when using an authorized business key.

import { Arc0 } from '@arc0/sdk';
import { randomUUID } from 'node:crypto';

const arc0 = new Arc0({
  baseUrl: process.env.ARC0_API_URL!,
  apiKey: process.env.ARC0_API_KEY!,
});

const shortlist = await arc0.search({ query: 'public repository' });
const tool = shortlist.tools.find((tool) => tool.action === 'github.get_public_repository');
if (!tool) throw new Error('Enable the public GitHub tool first');
const definition = await arc0.search({ action: tool.action, version: tool.version });
// Inspect definition.tools[0].inputSchema before constructing arguments.
const receipt = await arc0.execute({
  action: tool.action,
  actionVersion: tool.version,
  arguments: { owner: 'octocat', repo: 'Hello-World' },
  idempotencyKey: randomUUID(),
});

Search returns a small authorized shortlist. An exact action lookup adds its schemas. A tool can require a connection even when it appears in discovery. In that case, await arc0.connect({ app: 'github' }) returns a hosted setup URL for the person to open. Never ask an agent to collect provider passwords.

Save the idempotency key with your job. A retry must use the same key and identical arguments. The client never automatically retries execution. A timeout may mean the provider received the request; retrieve the receipt and reconcile before a new dispatch.

Use getExecution(id) to read a receipt or waitForExecution(id) to poll pending work. The poller returns approval states immediately so your application can request human approval. It never approves a call or repeats a provider write. Result reads enforce current access and retention; a previously successful call is not a permanent access grant.

HTTPS is required outside localhost. Redirects are rejected to prevent credentials from being forwarded to another destination.

Embed connections in your product

Create an Embedded integration key in the project's API keys screen. Keep it on your server; this key manages users and connections and can execute tools. Give your authenticated application user a stable external ID that includes your own tenant boundary where needed.

const management = new Arc0({ baseUrl: apiOrigin, apiKey: serverOnlyKey });
// Values come from your verified server session, never an arbitrary browser subject ID.
const user = await management.upsertUser({
  externalId: `${session.tenantId}:${session.userId}`,
  name: session.userName,
});
if (user.status !== 'active') throw new Error('User access is disabled');
const customer = new Arc0({ baseUrl: apiOrigin, apiKey: serverOnlyKey, endUserId: user.id });
const { url } = await customer.connect({ app: 'github', authMethod: 'oauth' });
// Return the short-lived hosted connection URL to this authenticated user only.
const connections = await customer.listConnections({ limit: 50 });
// After an explicit disconnect request and your ownership check:
await customer.revokeConnection(selectedOwnedConnectionId);

upsertUser requires users:manage; listing and revoking require connections:manage. These management operations require an unbound Embedded key. The constructor's endUserId scopes the SDK requests; it does not make a management key safe to expose in the browser. Connections paginate through nextCursor, and never return provider credentials.

For multi-app selection, use the unbound management client after provisioning the user:

const catalog = await management.listConnectableApps({ endUserId: user.id });
const sessionLink = await management.createConnectSession({
  endUserId: user.id,
  apps: ['github', 'slack'],
  expiresInSeconds: 600,
});

Catalog reads require connections:manage; session creation requires connect. Neither method accepts a client configured with constructor endUserId. Keep the returned capability URL secret and read Arc0 Connect for return-origin registration, reconnect restrictions and hosted catalog/browser client availability. Funded executions can also pass priceVersionId from the discovered offer to reject price changes; obtain spending consent before dispatch. Wallet funding and limit management use dashboard-session Core endpoints described in the API reference.

The repository's apps/acme is a local reference implementation with two synthetic customer identities, server-derived subject selection, hosted connection setup, profile reads and receipts. Its passwordless persona selector is a test harness, not production authentication. Use your real identity provider and tenant authorization in a deployed product.

On this page