MCPcopy Index your code
hub / github.com/camunda/camunda-8-js-sdk

github.com/camunda/camunda-8-js-sdk @v8.8.12

Chat with this repo
repository ↗ · DeepWiki ↗ · release v8.8.12 ↗ · + Follow
1,006 symbols 2,879 edges 273 files 233 documented · 23% updated 7d agov8.9.0-alpha.9 · 2026-07-02★ 3322 open issues

Browse by type

Functions 548 Types & classes 458
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Camunda 8 JavaScript SDK

NPM

License

SDK API docs. Orchestration Cluster API Client full API docs.

This is the official Camunda 8 JavaScript SDK. It is written in TypeScript and runs on Node.js. See why this SDK does not run in a web browser.

If you need to run an application in the web browser, then look at using the @camunda8/orchestration-cluster-api package directly.

See the Getting Started Example in the Camunda Docs for a quick start.

Which package should I use?

This SDK provides API clients for various versions of Camunda 8. If you are doing a greenfield project on Camunda 8.8 or later, then you should consider directly using the @camunda8/orchestration-cluster-api package. That package provides a client for the Camunda 8 Orchestration Cluster API, a REST API with full functionality.

This SDK includes that client, but relying on this SDK package pulls in other API clients, which - if you are not using them - exposes you to several factors:

  • Increased dependency size for dependencies that are irrelevant to your application
  • Node.js only. The other package runs in the browser.

How to choose?

Use the @camunda8/sdk package if:

  • You need the gRPC API to do Job Streaming.
  • Your server target is 8.7 or earlier.
  • You are progressively migrating an existing application to use the 8.8 Orchestration Cluster API.

Use the @camunda8/orchestration-cluster-api package directly if:

  • You are developing a green-field application.
  • Your server target is 8.8 or later.
  • You do not need to use the gRPC API.

Which API should I use?

The SDK provides clients for several Camunda 8 APIs.

If you are doing a greenfield project on Camunda 8.8.0 or later, then you should use the Camunda Orchestration Cluster API with getOrchestrationClusterApiClient. This is a REST API that provides complete cluster functionality in one API surface. This client is strongly typed and provides strong types for request and response fields (eg: ProcessInstanceKey, ProcessDefinitionId, etc).

To progressively adopt this client in existing projects alongside previous clients, you can call getOrchestrationClusterApiClientLoose to get a client that does not strongly type the request and response fields (they remain primitive scalar string type).

What does "supported" mean?

This is the official supported-by-Camunda Nodejs SDK for Camunda Platform 8.

The Node.js SDK will not always support all features of Camunda Platform 8 immediately upon their release. Complete API coverage for a platform release will lag behind the platform release.

Prioritisation of implementing features is influenced by customer demand.

Semantic versioning

The SDK package tracks Camunda Platform 8 minor versioning. Feature releases to support current Platform minor version features result in a patch release of the SDK.

Using the SDK in your project

Install the SDK as a dependency:

npm i @camunda8/sdk

Usage

The functionality of Camunda 8 is exposed via dedicated clients for the component APIs. The recommended API client for Camunda 8.8 is the Orchestration Cluster API, using the CamundaClient returned by getOrchestrationClusterApiClient().

import { Camunda8 } from '@camunda8/sdk'

const c8 = new Camunda8()

// Camunda 8 Orchestration Cluster API (STRICT client) - recommended from 8.8.0
// Provides strongly typed request & response IDs (e.g. ProcessInstanceKey, ProcessDefinitionId)
const orchestration = c8.getOrchestrationClusterApiClient()

// Camunda 8 Orchestration Cluster API (LOOSE client) - progressive adoption variant
// Same methods, but all IDs are plain string. Start here in existing codebases, then
// migrate to the strict client when convenient.
const orchestrationLoose = c8.getOrchestrationClusterApiClientLoose()

Configuration

The configuration for the SDK can be done by any combination of environment variables and explicit configuration passed to the Camunda8 constructor.

The recommended method of configuration is using the zero-conf constructor, which hydrates the configuration completely from the environment:

const camunda = new Camunda8()

This allows you to cleanly separate the concern of configuration from your code and locate it purely in environment variable management.

The complete documentation of all configuration parameters (environment variables) can be found here.

Any configuration passed in to the Camunda8 constructor is merged over any configuration in the environment. The configuration object fields and the environment variables have exactly the same names.

Orchestration Cluster API: Strict vs Loose Clients

From Camunda 8.8 onwards the unified Orchestration Cluster API is the preferred interface. This SDK exposes it via two factory methods to enable smooth, incremental migration:

Factory Purpose ID / Key Types Recommended Use
getOrchestrationClusterApiClient() Strict (strongly typed) client Branded TypeScript types (e.g. ProcessInstanceKey, ProcessDefinitionId) Greenfield projects or code already prepared for branded types
getOrchestrationClusterApiClientLoose() Loose client Plain string Progressive adoption in existing code expecting raw string IDs

Why two clients?

Branded (nominal) types significantly reduce accidental mixing of unrelated IDs (for example passing a decision definition id where a process instance key is expected). However, adopting them in an existing codebase can require refactors across many modules. The loose client lets you start calling the new endpoints immediately without touching those modules. You can then migrate incrementally to the strict client as you update code.

Migration Path

  1. Introduce the loose client alongside existing v1 component clients: const ocaLoose = c8.getOrchestrationClusterApiClientLoose().
  2. Replace calls to older clients (Operate / Tasklist / Optimize for read operations, Zeebe REST for workflow interactions) with equivalent Orchestration API calls using the loose client.
  3. When convenient, switch a module to the strict client: change imports to use getOrchestrationClusterApiClient() and address TypeScript compile errors by adopting the branded ID types (usually by propagating the type instead of string).
  4. Remove the loose client usage once all modules compile cleanly with the strict client.

REST Address Normalization (/v2)

Set ZEEBE_REST_ADDRESS without the version suffix; the SDK will append /v2 exactly once:

export ZEEBE_REST_ADDRESS='http://localhost:8888'

Results in effective base URL: http://localhost:8888/v2.

If you include /v2 already:

export ZEEBE_REST_ADDRESS='http://localhost:8888/v2'

It is preserved (not duplicated). Trailing slashes are stripped before normalization (http://localhost:8888/ -> http://localhost:8888/v2).

Choosing Between Clients

Use the strict client for new code, libraries, or examples where type safety improves clarity. Use the loose client when: - You need a rapid drop-in replacement without changing existing function signatures. - You are migrating many modules gradually. - You want to defer adoption of branded ID types until later.

Both clients expose identical method names and behaviors; only the TypeScript surface differs. Runtime semantics and responses are otherwise equivalent.

Example (Strict vs Loose)

import { Camunda8 } from '@camunda8/sdk'
const c8 = new Camunda8()

// Strict client (preferred once migrated)
const oca = c8.getOrchestrationClusterApiClient()
const proc = await oca.createProcessInstance({
  processDefinitionId: ProcessDefinitionId.assumeExists('order-process'),
  variables: { orderId: 'A123' },
})
// proc.processInstanceKey is a branded type (not a plain string)

// Loose client (progressive adoption)
const ocaLoose = c8.getOrchestrationClusterApiClientLoose()
const procLoose = await ocaLoose.createProcessInstance({
  processDefinitionId: 'order-process',
  variables: { orderId: 'B456' },
})
// procLoose.processInstanceKey is a plain string

When converting code from loose to strict, remove unnecessary casts like (key as string) and allow the compiler to guide corrections where branded types surface.

Lifting Legacy String IDs

To migrate existing code that uses plain strings for identifiers without immediately switching every module to the strict client, you can "lift" those strings into branded key types incrementally.

All branded key lifter namespaces are grouped under OrchestrationLifters so the root SDK export surface stays tidy:

import { OrchestrationLifters } from '@camunda8/sdk'

// Suppose you previously passed raw strings:
const rawProcessInstanceKey = '2251799813685249'

// Lift it to the branded type (runtime value is still a string, but type safety now applies):
const processInstanceKey = OrchestrationLifters.ProcessInstanceKey.assumeExists(rawProcessInstanceKey)

// Use with strict client
const c8 = new Camunda8()
const oca = c8.getOrchestrationClusterApiClient()
await oca.cancelProcessInstance({ processInstanceKey })

Common helper: assumeExists(value: string) turns a known-valid legacy identifier into its branded equivalent. Use this when you are certain the ID refers to an existing entity (the lifter does not perform a network validation; it is purely nominal typing).

Suggested incremental approach: 1. Start by replacing output values first (e.g. responses from createProcessInstance) where the strict client already returns branded types. 2. Introduce lifters at the boundaries where you still receive legacy strings (configuration, environment, persistence layer, legacy SDK modules). 3. Remove lifters once those boundaries natively produce branded types.

All available lifters (examples): ProcessInstanceKey, ProcessDefinitionId, JobKey, ElementInstanceKey, DecisionDefinitionKey, FormKey, UserTaskKey, VariableKey, etc. See OrchestrationLifters export for the complete list.

A note on how int64 is handled in the JavaScript SDK

Entity keys in Camunda 8.6 and earlier are stored and represented as int64 numbers. The range of int64 extends to numbers that cannot be represented by the JavaScript number type. To deal with this, int64 keys are serialised by the SDK to the JavaScript string type. See this issue for more details.

For int64 values whose type is not known ahead of time, such as job variables, you can pass an annotated data transfer object (DTO) to decode them reliably. See the section on Process Variable Typing. If no DTO is specified, the default behavior of the SDK is to serialise all numbers to JavaScript number, and to throw an exception if a number value is detected at a runtime that cannot be accurately represented as the JavaScript number type (that is, a value greater than 2^53-1).

Authorization

Calls to APIs can be authorized using a number of strategies. The most common is OAuth - a token that is obtained via a client id/secret pair exchange.

  • Camunda SaaS and Self-Managed by default are configured to use OAuth with token exchange. In most cases, you will use the OAUTH strategy and provide configuration only. The token exchange and its lifecycle are managed by the SDK in this strategy. This passes the token in the authorization header of requests.
  • If you secure the gateway behind an Nginx reverse-proxy secured with basic authentication, you will use the BASIC strategy. This adds the login credentials as the authorization header on requests.
  • For C8Run 8.7, you will need to use the COOKIE strategy. This manages a session cookie obtained from a login endpoint, and adds it as a cookie header to requests.
  • For more customisation, you can use the BEARER strategy. This is a strategy that allows you to dynamically provide the Bearer token directly. The currently set token is added as the authorization header on requests.
  • If you have a even more advanced use-case (for example, the need to add specific headers with specific values to authenticate with a proxy gateway), you can construct your own AuthProvider and pass it to the constructor.
  • You can also disable header auth completely and use mTLS (client certificate) — or no authentication at all — with the NONE strategy.

For more details on each of these scenarios, see the relevant section below.

Disable Auth

To disable Auth, set the environment variable CAMUNDA_AUTH_STRATEGY=NONE. You can use this when running against a minimal Zeebe broker in a development environment, for example. You can also use this when your authentication is being done using an x509 mTLS certificate (see the section on mTLS).

OAuth

If your platform is secured with OAuth token exchange (Camunda SaaS or Self-Managed with Identity), provide the following configuration fields at a minimum, either via the Camunda8 constructor or in environment variables:

CAMUNDA_AUTH_STRATEGY=OAUTH
ZEEBE_GRPC_ADDRESS=...
ZEEBE_REST_ADDRESS=...
ZEEBE_CLIENT_ID=...
ZEEBE_CLIENT_SECRET=...
CAMUNDA_OAUTH_URL=...

To get a token for

Extension points exported contracts — how you extend this code

Core symbols most depended-on inside this repo

Shape

Method 414
Interface 270
Class 186
Function 134
Enum 2

Languages

TypeScript100%

Modules by API surface

src/c8/lib/C8Dto.ts102 symbols
src/c8/lib/CamundaRestClient.ts67 symbols
src/zeebe/lib/interfaces-grpc-1.0.ts57 symbols
src/zeebe/lib/interfaces-1.0.ts46 symbols
src/admin/lib/AdminApiClient.ts40 symbols
src/zeebe/zb/ZeebeGrpcClient.ts34 symbols
src/operate/lib/OperateApiClient.ts29 symbols
src/modeler/lib/ModelerDto.ts29 symbols
src/modeler/lib/ModelerAPIClient.ts28 symbols
src/oauth/lib/OAuthProvider.ts27 symbols
src/operate/lib/OperateDto.ts26 symbols
src/c8/index.ts26 symbols

Datastores touched

web-modeler-dbDatabase · 1 repos

For agents

$ claude mcp add camunda-8-js-sdk \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page