Source: https://docs.cumuluslabs.io/sdk-reference/client
Content version: daf00625

# API client reference

Create a Cumulus client in your backend, then call a typed operation such as client.agents.list or client.runs.create. The client sends your API key, validates successful JSON responses and preserves the request key when a command’s result is uncertain. For agent definitions and publication, use the higher-level authoring functions in the agent module.

Import from `@cumulus/sdk`. This page documents SDK 0.3.4. Follow the [api client guide](/docs/api) for a worked workflow.

## Start with a working example {#example}

```typescript
import { Cumulus, PlatformError, type OperationInput } from "@cumulus/sdk";

export async function listAgents(baseUrl: string, apiKey: string) {
  const client = new Cumulus({ baseUrl, apiKey, timeoutMs: 30_000 });
  const input: OperationInput<"agents.list"> = { query: { limit: 20 } };
  try {
    const page = await client.agents.list(input);
    return page.agents;
  } catch (error) {
    if (error instanceof PlatformError) {
      // Return structured recovery information to your application's caller.
      return { code: error.code, retryable: error.retryable,
        outcome: error.outcome, status: error.status };
    }
    throw error;
  }
}
```

## Connect and make requests {#connect-and-make-requests}

### Cumulus {#cumulus}

Construct the typed REST client. Domain methods such as client.agents.list and client.runs.create accept OperationInput for their operation ID. call is the same transport addressed by ID; events and stream read server-sent events. A JSON events request uses client.runs.events instead.

Related types and helpers: [DomainMethods](/docs/sdk-reference/client#domainmethods) · [CumulusOptions](/docs/sdk-reference/client#cumulusoptions) · [OperationId](/docs/sdk-reference/client#operationid) · [OperationInput](/docs/sdk-reference/client#operationinput) · [OperationResult](/docs/sdk-reference/client#operationresult) · [SemanticEvent](/docs/sdk-reference/client#semanticevent) · [StreamOperationId](/docs/sdk-reference/client#streamoperationid).

```typescript-declaration
export interface Cumulus extends DomainMethods {
}

export declare class Cumulus {
    #private;
    constructor(options?: CumulusOptions);
    call<K extends OperationId>(operationId: K, input: OperationInput<K>, signal?: AbortSignal): Promise<OperationResult<K>>;
    /** runs.events as text/event-stream; resume with lastEventId (= last seen sequence). No client timeout. With
     * `onProgress`, the stream also carries live progress hints (`progress: "live"`: the run's transcript or effect ledger
     * moved), which go to the callback; only journal events are yielded. */
    events(input: OperationInput<"runs.events"> & {
        lastEventId?: string;
        onProgress?: (progress: RunProgress) => void;
    }, signal?: AbortSignal): AsyncGenerator<SemanticEvent>;
    /** Any journal operation served as text/event-stream (`stream: "sse"` in the registry: runs.events,
     * test_runs.events); resume with lastEventId (= last seen sequence). No client timeout. */
    stream<K extends StreamOperationId>(operationId: K, input: OperationInput<K> & {
        lastEventId?: string;
    }, signal?: AbortSignal, onProgress?: (progress: RunProgress) => void, onCursor?: (cursor: string) => void): AsyncGenerator<SemanticEvent>;
}
```

### listOperations {#listoperations}

Return the operation IDs understood by this installed SDK. Use it to inspect transport coverage or build a typed integration selector.

Related types and helpers: [OperationId](/docs/sdk-reference/client#operationid).

```typescript-declaration
export declare function listOperations(): readonly OperationId[];
```

### OPERATIONS {#operation-metadata}

Read the generated operation metadata: HTTP method, path, owner, read/command kind, idempotency rule, stream support and success status. Metadata describes transport, not authorization for the current key.

```typescript
import { OPERATIONS } from "@cumulus/sdk";

type CreateRunMetadata = (typeof OPERATIONS)["runs.create"];
const createRun: CreateRunMetadata = OPERATIONS["runs.create"];
```

Indexed access preserves the exact type from the installed package. Use the [customer HTTP API reference](/docs/api-reference) to choose supported customer operations; metadata alone does not establish authorization. The complete constant declarations remain available in the installed package for editor navigation.

### DOMAINS {#domain-metadata}

Read the nested operation-name tree installed on Cumulus instances. A leaf contains the stable operation ID used by call.

```typescript
import { DOMAINS } from "@cumulus/sdk";

type CreateRunId = (typeof DOMAINS)["runs"]["create"];
const createRunId: CreateRunId = DOMAINS.runs.create;
```

Indexed access preserves the exact type from the installed package. Use the [customer HTTP API reference](/docs/api-reference) to choose supported customer operations; metadata alone does not establish authorization. The complete constant declarations remain available in the installed package for editor navigation.

## Handle API failures {#handle-api-failures}

### PlatformError {#platformerror}

Inspect code, status, retryable, outcome, details and idempotencyKey after an API failure. outcome="unknown" means a command may have taken effect; reconcile or replay the original request key. Static constructors classify connection failures, lost acknowledgements and malformed owner responses; fromResponse preserves a valid API error envelope.

Related types and helpers: [ApiErrorCode](/docs/sdk-reference/client#apierrorcode) · [ApiErrorBody](/docs/sdk-reference/client#apierrorbody) · [OperationKind](/docs/sdk-reference/client#operationkind).

```typescript-declaration
/**
 * Every failure, typed. Transport failures are classified exactly like the MCP server
 * (packages/mcp-server/src/rest.ts): a connection that was never established is `internal` with
 * `outcome: "none"`; a command whose acknowledgement is lost is `outcome_unknown` with
 * `outcome: "unknown"` and carries the `idempotencyKey` to retry with.
 */
export declare class PlatformError extends Error {
    readonly status: number | null;
    readonly idempotencyKey?: string | undefined;
    readonly code: ApiErrorCode;
    readonly retryable: boolean;
    readonly outcome: "none" | "unknown";
    readonly details: Record<string, unknown>;
    constructor(error: ApiErrorBody["error"], status: number | null, idempotencyKey?: string | undefined, options?: {
        cause?: unknown;
    });
    /** A command whose result was not confirmed: it may have taken effect; retry with the same key. */
    static unconfirmed(status: number | null, idempotencyKey?: string, cause?: unknown): PlatformError;
    /** A read that failed in transport or on the owner: nothing took effect. */
    static unavailable(status: number | null, idempotencyKey?: string, cause?: unknown): PlatformError;
    /** A 2xx whose body could not be read as JSON. */
    static invalidResponse(kind: OperationKind, status: number, idempotencyKey?: string, cause?: unknown): PlatformError;
    static fromResponse(response: Response, kind: OperationKind, idempotencyKey?: string): Promise<PlatformError>;
    static transport(error: unknown, kind: OperationKind, idempotencyKey?: string): PlatformError;
}
```

## Types and declarations {#types}

### ApiErrorBody {#apierrorbody}

The API’s JSON error envelope. PlatformError exposes the nested error fields alongside HTTP status and request key.

Related types and helpers: [components](/docs/sdk-reference/client#components).

```typescript-declaration
export type ApiErrorBody = components["schemas"]["ApiError"];
```

### ApiErrorCode {#apierrorcode}

The exact code union from the API error schema. Branch on a code when your application has a specific recovery path.

Related types and helpers: [ApiErrorBody](/docs/sdk-reference/client#apierrorbody).

```typescript-declaration
export type ApiErrorCode = ApiErrorBody["error"]["code"];
```

### components {#components}

Complete named API schemas, including DraftEdit, native nodes, publication references, runs, events and errors. Types use components["schemas"]["Name"].

```typescript
import type { components } from "@cumulus/sdk";

type Run = components["schemas"]["Run"];
type NativeEdit = components["schemas"]["DraftEdit"];
```

The named schemas and HTTP payload fields are documented in the [HTTP API reference](/docs/api-reference) and the downloadable [OpenAPI contract](/docs/openapi.json). The installed package includes the complete declarations for editor navigation and type checking.

### CumulusOptions {#cumulusoptions}

Choose the API URL and credentials for your workspace. timeoutMs defaults to 30,000 for ordinary requests; streaming requests use the caller’s abort signal. baseUrl defaults to CUMULUS_BASE_URL, then https://api.cumuluslabs.io; apiKey defaults to CUMULUS_API_KEY. fetch defaults to globalThis.fetch. validateResponses defaults to true. Explicit talosUrl and controlPlaneUrl override the corresponding owner host. operationPaths overrides individual route paths and rejects relative, query-bearing or cross-origin path syntax.

Related types and helpers: [paths](/docs/sdk-reference/client#paths) · [OperationId](/docs/sdk-reference/client#operationid).

```typescript-declaration
export interface CumulusOptions {
    /** Sent as `Authorization: Bearer`. Default `CUMULUS_API_KEY`. Without a key no Authorization header is sent:
     * a browser client calls a same-origin proxy that authenticates the session cookie server-side. */
    apiKey?: string;
    /** Every operation's host (D18: one public API host). Default `CUMULUS_BASE_URL` or https://api.cumuluslabs.io.
     * A relative URL (`/cp-proxy`) resolves against the page location in a browser. */
    baseUrl?: string;
    /** Per-owner hosts for a split deployment (a local stack serves Talos and the control plane apart). */
    talosUrl?: string;
    controlPlaneUrl?: string;
    fetch?: typeof fetch;
    timeoutMs?: number;
    /** Deployment paths keyed by stable contract operation ID. */
    operationPaths?: Partial<Record<OperationId, string>>;
    /** Defaults true. Disable only for deliberately partial transport fixtures. */
    validateResponses?: boolean;
}
```

### DomainMethods {#domainmethods}

The mapped type behind client.<domain>.<method>. Each leaf accepts its own OperationInput and returns Promise<OperationResult>. Deeper operation names form nested namespaces.

```typescript-declaration
export type DomainMethods = Methods<Domains>;
```

### OperationBody {#operationbody}

Select the JSON request body for an operation, useful when a function constructs or validates its own request data.

Related types and helpers: [OperationId](/docs/sdk-reference/client#operationid).

```typescript-declaration
export type OperationBody<K extends OperationId> = Op<K> extends {
    requestBody: infer R;
} ? Json<R> : never;
```

### OperationId {#operationid}

The union of stable operation IDs shipped in this SDK. Use it as the key for typed calls and operation metadata.

Related types and helpers: [operations](/docs/sdk-reference/client#operations).

```typescript-declaration
export type OperationId = keyof operations;
```

### OperationInput {#operationinput}

Combine the operation’s required path/body values, optional query and optional idempotencyKey. Fields that do not exist for that operation are unavailable in the type.

Related types and helpers: [OperationId](/docs/sdk-reference/client#operationid) · [OperationPath](/docs/sdk-reference/client#operationpath) · [OperationQuery](/docs/sdk-reference/client#operationquery) · [OperationBody](/docs/sdk-reference/client#operationbody).

```typescript-declaration
export type OperationInput<K extends OperationId> = Part<"path", OperationPath<K>, false> & Part<"query", OperationQuery<K>, true> & Part<"body", OperationBody<K>, false> & {
    idempotencyKey?: string;
};
```

### OperationKind {#operationkind}

Distinguish a read from a command when classifying transport failures. A lost command response can have an unknown outcome.

```typescript-declaration
export type OperationKind = "read" | "command";
```

### OperationMeta {#operationmeta}

The transport information associated with one OperationId. See OPERATIONS for the generated values.

```typescript-declaration
export interface OperationMeta {
    method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
    path: string;
    owner: "talos" | "control-plane";
    kind: "read" | "command";
    idempotency: "required_header" | "natural" | "none";
    stream: "sse" | null;
    successStatus: number;
}
```

### OperationPath {#operationpath}

Select the path parameter object for an operation, such as {run_id: string} for runs.get.

Related types and helpers: [OperationId](/docs/sdk-reference/client#operationid).

```typescript-declaration
export type OperationPath<K extends OperationId> = Op<K> extends {
    parameters: {
        path: infer P;
    };
} ? P : never;
```

### OperationQuery {#operationquery}

Select the query parameter object for an operation. The client omits null and undefined query values before sending.

Related types and helpers: [OperationId](/docs/sdk-reference/client#operationid).

```typescript-declaration
export type OperationQuery<K extends OperationId> = Op<K> extends {
    parameters: {
        query?: infer Q;
    };
} ? NonNullable<Q> : never;
```

### OperationResult {#operationresult}

Select the JSON response type for an operation’s successful 200, 201 or 202 response.

Related types and helpers: [OperationId](/docs/sdk-reference/client#operationid).

```typescript-declaration
export type OperationResult<K extends OperationId> = Op<K> extends {
    responses: infer R;
} ? {
    [S in keyof R]: S extends 200 | 201 | 202 ? Json<R[S]> : never;
}[keyof R] : never;
```

### operations {#operations}

Complete operation request and response declarations. Prefer OperationInput and OperationResult for application code; use this map when building transport tooling.

```typescript
import type { operations } from "@cumulus/sdk";

type CreateRun = operations["runs.create"];
type RunBody = CreateRun["requestBody"]["content"]["application/json"];
```

The named schemas and HTTP payload fields are documented in the [HTTP API reference](/docs/api-reference) and the downloadable [OpenAPI contract](/docs/openapi.json). The installed package includes the complete declarations for editor navigation and type checking.

### paths {#paths}

Complete HTTP path declarations and their available methods. This is the route-oriented view of the same generated API contract.

```typescript
import type { paths } from "@cumulus/sdk";

type CreateRun = paths["/api/v1/runs"]["post"];
type RunResponse = CreateRun["responses"][201]["content"]["application/json"];
```

The named schemas and HTTP payload fields are documented in the [HTTP API reference](/docs/api-reference) and the downloadable [OpenAPI contract](/docs/openapi.json). The installed package includes the complete declarations for editor navigation and type checking.

### SemanticEvent {#semanticevent}

A durable event from the run journal. Persist event identity and reconnect position after handling it; event contents are data from the run.

Related types and helpers: [components](/docs/sdk-reference/client#components).

```typescript-declaration
export type SemanticEvent = components["schemas"]["SemanticEvent"];
```

### StreamOperationId {#streamoperationid}

The operation IDs supporting server-sent events. Cumulus.stream accepts only this subset.

Related types and helpers: [Cumulus](/docs/sdk-reference/client#cumulus) · [OperationId](/docs/sdk-reference/client#operationid) · [OPERATIONS](/docs/sdk-reference/client#operation-metadata).

```typescript-declaration
/** Operations the registry serves as text/event-stream (`Cumulus.stream`). */
export type StreamOperationId = {
    [K in OperationId]: (typeof OPERATIONS)[K]["stream"] extends "sse" ? K : never;
}[OperationId];
```

## Supporting types {#supporting-types}

These local type expressions appear in the signatures above. They are not separate package exports.

```typescript-declaration
type Op<K extends OperationId> = operations[K];

type Json<T> = T extends {
    content: {
        "application/json": infer B;
    };
} ? B : never;

type Part<Key extends string, T, Optional extends boolean> = [
    T
] extends [
    never
] ? {
    [P in Key]?: undefined;
} : Optional extends true ? {
    [P in Key]?: T;
} : {
    [P in Key]: T;
};

type Domains = typeof DOMAINS;

/** `client.<domain>.<method>`; an operation id with more segments nests (`client.session.act_as.enter`). */
type Methods<T> = {
    readonly [K in keyof T]: T[K] extends OperationId ? (input: OperationInput<T[K]>, signal?: AbortSignal) => Promise<OperationResult<T[K]>> : Methods<T[K]>;
};
```

## Export index {#exports}

- **Connect and make requests:** [Cumulus](#cumulus) · [listOperations](#listoperations) · [OPERATIONS](#operation-metadata) · [DOMAINS](#domain-metadata)
- **Handle API failures:** [PlatformError](#platformerror)
- **Types:** [ApiErrorBody](#apierrorbody) · [ApiErrorCode](#apierrorcode) · [components](#components) · [CumulusOptions](#cumulusoptions) · [DomainMethods](#domainmethods) · [OperationBody](#operationbody) · [OperationId](#operationid) · [OperationInput](#operationinput) · [OperationKind](#operationkind) · [OperationMeta](#operationmeta) · [OperationPath](#operationpath) · [OperationQuery](#operationquery) · [OperationResult](#operationresult) · [operations](#operations) · [paths](#paths) · [SemanticEvent](#semanticevent) · [StreamOperationId](#streamoperationid)
