Skip to content

@bpmn-sdk/api

Overview

@bpmn-sdk/api is a complete TypeScript client for the Camunda 8 Orchestration Cluster REST API:

  • 180 typed methods across 30+ resource classes
  • Auth: OAuth2, Bearer token, Basic, and no-auth
  • LRU+TTL cache for read-heavy operations
  • Exponential backoff with configurable retry
  • TypedEventEmitter for observability hooks
  • Zero transitive runtime dependencies

Installation

Terminal window
pnpm add @bpmn-sdk/api

Client Configuration

import { CamundaClient } from "@bpmn-sdk/api";
const client = new CamundaClient({
baseUrl: "https://api.cloud.camunda.io",
auth: {
type: "oauth2",
clientId: process.env.CAMUNDA_CLIENT_ID,
clientSecret: process.env.CAMUNDA_CLIENT_SECRET,
audience: process.env.CAMUNDA_AUDIENCE,
tokenUrl: process.env.CAMUNDA_TOKEN_URL,
},
// Optional:
cache: {
maxSize: 500, // LRU cache size (default: 200)
ttlMs: 30_000, // cache TTL in ms (default: 60_000)
},
retry: {
maxAttempts: 3, // default: 3
initialDelayMs: 200,
maxDelayMs: 5_000,
},
});

Resource Namespaces

All methods are grouped by resource type:

NamespaceMethods
client.processdeploy, startInstance, listInstances, getInstance, cancel, migrate
client.jobsactivate, complete, fail, throwError, activateAndProcess
client.incidentslist, resolve, get
client.variableslist, get, update
client.decisionsevaluate, list, getInstance
client.messagespublish, correlate
client.signalsbroadcast
client.userTaskslist, get, complete, assign, claim
client.userslist, get, create, delete
client.groupslist, get, create, assignMember
client.authorizationslist, create, delete

Process Operations

// Deploy
const deployed = await client.process.deploy({
resources: [{ content: bpmnXml, name: "my-flow.bpmn" }],
});
// Start instance
const instance = await client.process.startInstance({
bpmnProcessId: "my-flow",
variables: { customerId: "cust-001" },
});
// List active instances
const { items } = await client.process.listInstances({
state: "ACTIVE",
bpmnProcessId: "my-flow",
});
// Cancel instance
await client.process.cancel({
processInstanceKey: instance.processInstanceKey,
});

Job Workers

// Activate and handle jobs in a poll loop
const worker = await client.jobs.activateAndProcess({
type: "send-email",
maxJobsToActivate: 10,
timeout: 60_000, // job lock duration in ms
worker: "email-worker-1",
handler: async (job) => {
try {
await sendEmail(job.variables);
await client.jobs.complete({
jobKey: job.key,
variables: { emailSent: true },
});
} catch (err) {
await client.jobs.fail({
jobKey: job.key,
errorMessage: String(err),
retries: job.retries - 1,
});
}
},
});
// Stop polling
worker.close();

Incident Resolution

// Find all incidents for a process instance
const { items: incidents } = await client.incidents.list({
processInstanceKey: instance.processInstanceKey,
});
// Fix the problem in your code, then resolve
for (const incident of incidents) {
await client.incidents.resolve({ incidentKey: incident.key });
}

Message Correlation

await client.messages.publish({
messageName: "payment-confirmed",
correlationKey: "ord-456",
variables: {
paymentMethod: "card",
confirmedAt: new Date().toISOString(),
},
timeToLive: 60_000, // ms — how long to wait for a matching instance
});

Observability Events

type ClientEvent = "request" | "response" | "error" | "retry" | "token-refresh";
client.on("request", (e) => logger.debug(e.method, e.url));
client.on("response", (e) => metrics.histogram("api.latency", e.durationMs));
client.on("error", (e) => logger.error(e.status, e.url, e.body));
client.on("retry", (e) => logger.warn(`Retrying ${e.url} (attempt ${e.attempt})`));