# Camunda 8 Camunda 8 is a process automation and orchestration platform that enables organizations to design, execute, and monitor BPMN workflows and DMN decision models at scale. The platform provides a comprehensive suite of components including Zeebe (the workflow engine), Operate (for monitoring), Tasklist (for human task management), and Optimize (for analytics), along with official SDKs for Java, Python, C#, and JavaScript/TypeScript. The platform offers both SaaS and Self-Managed deployment options, with a unified Orchestration Cluster REST API (v2) for programmatic interaction. Key capabilities include deploying process definitions, starting and managing process instances, implementing job workers to handle automated tasks, managing user tasks, resolving incidents, and querying process data. The platform supports multiple authentication methods including OAuth 2.0/OIDC, basic authentication, and no-auth for local development. ## Orchestration Cluster REST API - Get Cluster Topology The topology endpoint returns information about the cluster configuration including brokers, partitions, and their states. This is commonly used to verify connectivity and check cluster health. ```bash # Local development (Camunda 8 Run / Docker Compose) curl http://localhost:8080/v2/topology # Camunda 8 SaaS with public connectivity curl -H "Authorization: Bearer ${ACCESS_TOKEN}" \ "https://${REGION_ID}.api.camunda.io/${CLUSTER_ID}/v2/topology" # Response example: # { # "gatewayVersion": "8.9.0", # "clusterSize": 3, # "partitionsCount": 3, # "replicationFactor": 3, # "brokers": [...] # } ``` ## Orchestration Cluster REST API - Deploy Resources Deploys BPMN processes, DMN decision models, or forms to the cluster. This is an atomic operation - either all resources deploy successfully or none do. Returns deployment metadata including generated keys for each resource. ```bash # Deploy a BPMN process file curl -X POST "http://localhost:8080/v2/deployments" \ -H "Content-Type: multipart/form-data" \ -F "resources=@process.bpmn" # Deploy multiple resources with tenant ID curl -X POST "http://localhost:8080/v2/deployments" \ -H "Content-Type: multipart/form-data" \ -F "resources=@process.bpmn" \ -F "resources=@decision.dmn" \ -F "tenantId=customer-service" # Response example: # { # "deploymentKey": "2251799813685249", # "tenantId": "", # "deployments": [ # { # "processDefinition": { # "processDefinitionId": "my-process", # "processDefinitionKey": "2251799813686749", # "processDefinitionVersion": 1, # "resourceName": "process.bpmn", # "tenantId": "" # } # } # ] # } ``` ## Orchestration Cluster REST API - Create Process Instance Creates and starts a new instance of a deployed process definition. Supports specifying the process by definition key or by BPMN process ID. Can optionally wait for completion with `awaitCompletion`. ```bash # Start process instance by definition key curl -X POST "http://localhost:8080/v2/process-instances" \ -H "Content-Type: application/json" \ -d '{ "processDefinitionKey": "2251799813686749", "variables": { "orderId": "12345", "amount": 100.0, "customerEmail": "customer@example.com" } }' # Start process instance by BPMN process ID (uses latest version) curl -X POST "http://localhost:8080/v2/process-instances" \ -H "Content-Type: application/json" \ -d '{ "processDefinitionId": "order-fulfillment", "variables": { "orderId": "12345" } }' # Start and wait for completion (for short-running processes) curl -X POST "http://localhost:8080/v2/process-instances" \ -H "Content-Type: application/json" \ -d '{ "processDefinitionId": "calculate-price", "variables": {"items": [{"sku": "A1", "qty": 2}]}, "awaitCompletion": true, "requestTimeout": 30000 }' # Response example: # { # "processDefinitionId": "order-fulfillment", # "processDefinitionKey": "2251799813686749", # "processDefinitionVersion": 1, # "processInstanceKey": "2251799813690746", # "tenantId": "", # "variables": {}, # "tags": [], # "businessId": null # } ``` ## Orchestration Cluster REST API - Complete User Task Completes a user task that was assigned to a user or claimed. Allows passing output variables and optionally action/variables for form-based tasks. ```bash # Complete a user task with variables curl -X POST "http://localhost:8080/v2/user-tasks/2251799813690755/completion" \ -H "Content-Type: application/json" \ -d '{ "variables": { "approved": true, "reviewComments": "Looks good, approved." } }' # Assign a user task curl -X POST "http://localhost:8080/v2/user-tasks/2251799813690755/assignment" \ -H "Content-Type: application/json" \ -d '{ "assignee": "john.doe" }' # Search for user tasks curl -X POST "http://localhost:8080/v2/user-tasks/search" \ -H "Content-Type: application/json" \ -d '{ "filter": { "state": "CREATED", "assignee": "john.doe" }, "sort": [{"field": "creationDate", "order": "DESC"}], "page": {"limit": 20} }' ``` ## Orchestration Cluster REST API - Correlate Message Publishes a message to trigger message catch events or start message events in process instances. Uses correlation keys to target specific process instances. ```bash # Publish a message to correlate with waiting process instances curl -X POST "http://localhost:8080/v2/messages/publication" \ -H "Content-Type: application/json" \ -d '{ "name": "payment-received", "correlationKey": "order-12345", "timeToLive": 60000, "variables": { "paymentId": "PAY-98765", "amount": 150.00, "status": "completed" } }' # Correlate a message (alternative endpoint) curl -X POST "http://localhost:8080/v2/messages/correlation" \ -H "Content-Type: application/json" \ -d '{ "name": "order-shipped", "correlationKey": "order-12345", "variables": { "trackingNumber": "1Z999AA10123456784" } }' ``` ## Java Client - Getting Started The Camunda Java Client is the official library for building process applications in Java. It provides full Orchestration Cluster API support with both REST and gRPC protocols, automatic token management, and built-in retry mechanisms. ```java // Maven dependency // // io.camunda // camunda-client-java // 8.9.x // import io.camunda.client.CamundaClient; import io.camunda.client.api.response.DeploymentEvent; import io.camunda.client.api.response.ProcessInstanceEvent; import java.net.URI; import java.util.Map; public class CamundaExample { public static void main(String[] args) { // Connect to local cluster (no authentication) try (CamundaClient client = CamundaClient.newClientBuilder() .grpcAddress(URI.create("http://localhost:26500")) .restAddress(URI.create("http://localhost:8080")) .build()) { // Test connection client.newTopologyRequest().execute(); System.out.println("Connected to Camunda 8!"); // Deploy a process DeploymentEvent deployment = client.newDeployResourceCommand() .addResourceFromClasspath("order-process.bpmn") .execute(); System.out.println("Deployed: " + deployment.getProcesses().get(0).getBpmnProcessId()); // Start a process instance ProcessInstanceEvent instance = client.newCreateInstanceCommand() .bpmnProcessId("order-process") .latestVersion() .variables(Map.of( "orderId", "ORD-12345", "customerName", "John Doe", "amount", 99.99 )) .execute(); System.out.println("Started instance: " + instance.getProcessInstanceKey()); } } } ``` ## Java Client - Connect to SaaS Connect to Camunda 8 SaaS using cluster credentials from the Camunda Console. The cloud client builder handles OAuth authentication automatically. ```java import io.camunda.client.CamundaClient; public class SaaSConnection { public static void main(String[] args) { // Using cloud client builder (recommended for SaaS) try (CamundaClient client = CamundaClient.newCloudClientBuilder() .withClusterId("your-cluster-id") .withClientId("your-client-id") .withClientSecret("your-client-secret") .withRegion("bru-2") // e.g., bru-2, syd-1 .build()) { client.newTopologyRequest().execute(); System.out.println("Connected to Camunda 8 SaaS!"); } // Alternative: Using environment variables // Set: CAMUNDA_CLIENT_ID, CAMUNDA_CLIENT_SECRET, CAMUNDA_CLUSTER_ID, etc. try (CamundaClient client = CamundaClient.newClientBuilder().build()) { // Client auto-configures from environment } } } ``` ## Java Client - Job Worker Job workers subscribe to specific job types and execute business logic when jobs become available. They handle polling, concurrent dispatch, auto-completion, and error handling automatically. ```java import io.camunda.client.CamundaClient; import io.camunda.client.api.worker.JobWorker; import io.camunda.client.api.worker.JobHandler; import io.camunda.client.api.worker.JobClient; import io.camunda.client.api.response.ActivatedJob; import java.time.Duration; import java.util.Map; public class JobWorkerExample { public static void main(String[] args) throws InterruptedException { try (CamundaClient client = CamundaClient.newClientBuilder().build()) { // Create a job worker try (JobWorker worker = client.newWorker() .jobType("send-email") .handler(new EmailJobHandler()) .timeout(Duration.ofMinutes(5)) .maxJobsActive(10) .open()) { System.out.println("Job worker started, listening for 'send-email' jobs..."); Thread.sleep(Duration.ofMinutes(10)); } } } static class EmailJobHandler implements JobHandler { @Override public void handle(JobClient client, ActivatedJob job) { // Get job variables Map variables = job.getVariablesAsMap(); String recipient = (String) variables.get("customerEmail"); String orderId = (String) variables.get("orderId"); System.out.println("Sending email to " + recipient + " for order " + orderId); // Simulate sending email boolean emailSent = sendEmail(recipient, "Order " + orderId + " confirmed"); if (emailSent) { // Complete the job with output variables client.newCompleteCommand(job.getKey()) .variables(Map.of("emailSent", true, "sentAt", System.currentTimeMillis())) .send() .join(); } else { // Fail the job with retry client.newFailCommand(job.getKey()) .retries(job.getRetries() - 1) .errorMessage("Failed to send email") .retryBackoff(Duration.ofSeconds(30)) .send() .join(); } } private boolean sendEmail(String to, String subject) { // Email sending logic here return true; } } } ``` ## Spring Boot Starter - Getting Started The Camunda Spring Boot Starter integrates Camunda 8 into Spring Boot applications with minimal configuration. It provides annotation-based job workers and automatic deployment. ```java // pom.xml dependency: // // io.camunda // camunda-spring-boot-starter // 8.9.x // // application.yaml for local development: // camunda: // client: // mode: self-managed // auth: // method: none // grpc-address: http://localhost:26500 // rest-address: http://localhost:8080 // application.yaml for SaaS: // camunda: // client: // mode: saas // auth: // client-id: your-client-id // client-secret: your-client-secret // cloud: // cluster-id: your-cluster-id // region: bru-2 import io.camunda.client.CamundaClient; import io.camunda.spring.client.annotation.Deployment; import io.camunda.spring.client.annotation.JobWorker; import io.camunda.spring.client.annotation.Variable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.stereotype.Component; import java.util.Map; @SpringBootApplication @Deployment(resources = "classpath:order-process.bpmn") public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } @Autowired private CamundaClient client; public void startOrder(String orderId, double amount) { client.newCreateInstanceCommand() .bpmnProcessId("order-process") .latestVersion() .variables(Map.of("orderId", orderId, "amount", amount)) .send() .join(); } } @Component class OrderWorkers { @JobWorker(type = "validate-order") public Map validateOrder( @Variable String orderId, @Variable double amount) { boolean isValid = amount > 0 && orderId != null; return Map.of("orderValid", isValid); } @JobWorker(type = "process-payment") public void processPayment(@Variable String orderId, @Variable double amount) { System.out.println("Processing payment of $" + amount + " for order " + orderId); // Payment processing logic } @JobWorker(type = "ship-order") public Map shipOrder(@Variable String orderId) { String trackingNumber = "TRK-" + System.currentTimeMillis(); return Map.of("trackingNumber", trackingNumber, "shipped", true); } } ``` ## Python SDK - Getting Started The Camunda Python SDK provides both synchronous (`CamundaClient`) and asynchronous (`CamundaAsyncClient`) clients. Job workers require the async client. ```python # Installation: pip install camunda-orchestration-sdk # Environment variables for zero-config setup: # CAMUNDA_REST_ADDRESS=http://localhost:8080 # For SaaS: # CAMUNDA_CLIENT_ID=your-client-id # CAMUNDA_CLIENT_SECRET=your-client-secret # CAMUNDA_REST_ADDRESS=https://region.api.camunda.io/cluster-id from camunda_orchestration_sdk import CamundaClient, ProcessCreationByKey # Synchronous client - for scripts, CLI tools, Django/Flask handlers with CamundaClient() as client: # Check connection topology = client.get_topology() print(f"Connected to Camunda {topology.gateway_version}") # Deploy a process deployment = client.deploy_resources_from_files(["order-process.bpmn"]) process_key = deployment.processes[0].process_definition_key print(f"Deployed process with key: {process_key}") # Start a process instance result = client.create_process_instance( data=ProcessCreationByKey( process_definition_key=process_key, variables={"orderId": "ORD-12345", "amount": 99.99} ) ) print(f"Started instance: {result.process_instance_key}") ``` ## Python SDK - Async Client and Job Workers The async client is required for job workers and provides better performance for I/O-bound operations in async frameworks like FastAPI. ```python import asyncio from camunda_orchestration_sdk import ( CamundaAsyncClient, ConnectedJobContext, WorkerConfig, JobFailure, JobError, MessagePublicationRequest, MessagePublicationRequestVariables ) async def handle_validate_order(job: ConnectedJobContext) -> dict[str, object]: """Validate order job handler""" variables = job.variables.to_dict() order_id = variables.get("orderId") amount = variables.get("amount", 0) job.log.info(f"Validating order {order_id} with amount {amount}") if amount <= 0: # Throw BPMN error to trigger error boundary event raise JobError(error_code="INVALID_AMOUNT", message="Order amount must be positive") if not order_id: # Fail with retry raise JobFailure( message="Missing order ID", retries=2, retry_back_off=5000 ) return {"orderValid": True, "validatedAt": "2024-01-15T10:30:00Z"} async def handle_send_notification(job: ConnectedJobContext) -> dict[str, object]: """Send notification and publish message to another process""" variables = job.variables.to_dict() order_id = variables["orderId"] # Use the client from job context to publish a message await job.client.publish_message( data=MessagePublicationRequest( name="order-completed", correlation_key=order_id, time_to_live=60000, variables=MessagePublicationRequestVariables.from_dict({ "orderId": order_id, "status": "completed" }) ) ) job.log.info(f"Published order-completed message for {order_id}") return {"notificationSent": True} async def main(): async with CamundaAsyncClient() as client: # Create job workers client.create_job_worker( config=WorkerConfig( job_type="validate-order", job_timeout_milliseconds=30_000, max_concurrent_jobs=10 ), callback=handle_validate_order ) client.create_job_worker( config=WorkerConfig( job_type="send-notification", job_timeout_milliseconds=60_000 ), callback=handle_send_notification ) print("Workers started, press Ctrl+C to stop...") await client.run_workers() asyncio.run(main()) ``` ## C# SDK - Getting Started The Camunda C# SDK (technical preview in 8.9, fully supported in 8.10) provides a modern, strongly-typed API for .NET applications with automatic configuration from environment variables. ```csharp // NuGet: dotnet add package Camunda.Orchestration.Sdk // Environment variables: // CAMUNDA_REST_ADDRESS=http://localhost:8080 // For SaaS: CAMUNDA_CLIENT_ID, CAMUNDA_CLIENT_SECRET, etc. using Camunda.Orchestration.Sdk; // Create client with zero configuration (uses environment variables) using var client = CamundaClient.Create(); // Deploy a process var deployment = await client.DeployResourcesFromFilesAsync(["order-process.bpmn"]); var processKey = deployment.Processes[0].ProcessDefinitionKey; Console.WriteLine($"Deployed process: {processKey}"); // Start a process instance var result = await client.CreateProcessInstanceAsync( new ProcessInstanceCreationInstructionByKey { ProcessDefinitionKey = processKey, Variables = new { orderId = "ORD-12345", amount = 99.99 } }); Console.WriteLine($"Started instance: {result.ProcessInstanceKey}"); // Or start by BPMN process ID var resultById = await client.CreateProcessInstanceAsync( new ProcessInstanceCreationInstructionById { ProcessDefinitionId = ProcessDefinitionId.AssumeExists("order-process") }); ``` ## C# SDK - Job Workers C# job workers use async handlers with automatic completion. Return values become output variables, and exceptions trigger failures or BPMN errors. ```csharp using Camunda.Orchestration.Sdk; // Define input/output types public record OrderInput(string OrderId, decimal Amount, string CustomerEmail); public record OrderOutput(bool Processed, string InvoiceNumber); using var client = CamundaClient.Create(); // Job worker with typed input/output client.CreateJobWorker( new JobWorkerConfig { JobType = "process-order", JobTimeoutMs = 30_000, MaxConcurrentJobs = 10 }, async (job, ct) => { var input = job.GetVariables(); Console.WriteLine($"Processing order {input!.OrderId} for ${input.Amount}"); // Simulate processing await Task.Delay(100, ct); // Return value auto-completes the job with these output variables return new OrderOutput(true, $"INV-{DateTime.UtcNow:yyyyMMddHHmmss}"); }); // Worker with error handling client.CreateJobWorker( new JobWorkerConfig { JobType = "validate-payment", JobTimeoutMs = 30_000 }, async (job, ct) => { var vars = job.GetVariables(); if (vars!.amount > 10000) { // Throw BPMN error - caught by error boundary events throw new BpmnErrorException("AMOUNT_TOO_HIGH", "Payment exceeds limit"); } if (vars.paymentMethod == null) { // Explicit failure with retry control throw new JobFailureException( "Missing payment method", retries: 2, retryBackOffMs: 5000 ); } return new { validated = true }; }); // Block until Ctrl+C using var cts = new CancellationTokenSource(); Console.CancelKeyPress += (_, e) => { e.Cancel = true; cts.Cancel(); }; await client.RunWorkersAsync(ct: cts.Token); ``` ## Operate API - Search Process Instances The Operate API provides search, filtering, and data export capabilities for process instances, incidents, and flow node instances. It complements the Orchestration Cluster API for read-heavy operations. ```bash # Search process instances with filters curl -X POST "http://localhost:8080/v1/process-instances/search" \ -H "Content-Type: application/json" \ -d '{ "filter": { "bpmnProcessId": "order-process", "state": "ACTIVE" }, "size": 50, "sort": [{"field": "startDate", "order": "DESC"}] }' # Response includes pagination via sortValues # { # "items": [ # { # "key": 2251799813699213, # "processVersion": 2, # "bpmnProcessId": "order-process", # "startDate": "2024-01-15T11:53:41.758+0000", # "state": "ACTIVE", # "processDefinitionKey": 2251799813695996 # } # ], # "sortValues": ["order-process", 2251799813699213], # "total": 654 # } # Get next page using sortValues curl -X POST "http://localhost:8080/v1/process-instances/search" \ -H "Content-Type: application/json" \ -d '{ "filter": {"bpmnProcessId": "order-process", "state": "ACTIVE"}, "size": 50, "sort": [{"field": "startDate", "order": "DESC"}], "searchAfter": ["order-process", 2251799813699213] }' # Get a specific process instance curl "http://localhost:8080/v1/process-instances/2251799813699213" # Delete a process instance and all dependent data curl -X DELETE "http://localhost:8080/v1/process-instances/2251799813699213" ``` ## Authentication - OAuth 2.0 Token Retrieval For SaaS and Self-Managed deployments with OIDC, obtain an access token using OAuth 2.0 client credentials flow before making API calls. ```bash # Camunda 8 SaaS - Get access token curl -X POST "https://login.cloud.camunda.io/oauth/token" \ -H "Content-Type: application/json" \ -d '{ "grant_type": "client_credentials", "audience": "zeebe.camunda.io", "client_id": "your-client-id", "client_secret": "your-client-secret" }' # Self-Managed with Keycloak curl -X POST "http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=your-client-id" \ -d "client_secret=your-client-secret" # Use the token in API requests ACCESS_TOKEN="eyJhbGc..." curl -H "Authorization: Bearer ${ACCESS_TOKEN}" \ "http://localhost:8080/v2/topology" ``` ```javascript // JavaScript/Node.js token retrieval const axios = require('axios'); async function getAccessToken() { const response = await axios.post( 'https://login.cloud.camunda.io/oauth/token', { grant_type: 'client_credentials', audience: 'zeebe.camunda.io', client_id: process.env.CAMUNDA_CLIENT_ID, client_secret: process.env.CAMUNDA_CLIENT_SECRET } ); return response.data.access_token; } // Use with API calls const token = await getAccessToken(); const topology = await axios.get( `https://${REGION}.api.camunda.io/${CLUSTER_ID}/v2/topology`, { headers: { Authorization: `Bearer ${token}` } } ); ``` ## Zeebe gRPC API - High-Performance Communication The Zeebe gRPC API provides low-latency, high-throughput communication for job activation and process operations. Ideal for high-volume workloads. ```java // Java gRPC client configuration import io.camunda.client.CamundaClient; import io.camunda.client.CamundaClientBuilder; // Configure client to prefer gRPC for job activation CamundaClient client = CamundaClient.newClientBuilder() .grpcAddress(URI.create("http://localhost:26500")) .restAddress(URI.create("http://localhost:8080")) .preferGrpcOverRest(true) // Use gRPC for compatible operations .build(); // Job worker with streaming (gRPC-specific feature) JobWorker worker = client.newWorker() .jobType("high-throughput-task") .handler(jobHandler) .streamEnabled(true) // Enable job streaming for lower latency .streamTimeout(Duration.ofMinutes(30)) .maxJobsActive(64) .open(); ``` ```python # Python - gRPC is used internally by the SDK when configured # Environment: CAMUNDA_GRPC_ADDRESS=http://localhost:26500 from camunda_orchestration_sdk import CamundaAsyncClient, WorkerConfig async with CamundaAsyncClient() as client: # Workers automatically use optimized polling client.create_job_worker( config=WorkerConfig( job_type="high-throughput-task", job_timeout_milliseconds=30_000, max_concurrent_jobs=64, request_timeout_milliseconds=20_000 # Long-poll timeout ), callback=my_handler ) ``` ## Summary Camunda 8 provides a comprehensive process automation platform designed for microservices architectures and cloud-native deployments. The main use cases include orchestrating business processes across distributed systems, implementing human task workflows with custom task applications, automating decision-making with DMN, and building event-driven integrations. The platform excels at handling complex, long-running processes that span multiple services and require visibility, monitoring, and incident management. Integration patterns typically involve deploying BPMN processes that define the workflow, implementing job workers in your preferred language (Java, Python, C#, or TypeScript) to handle service tasks, using the REST API for process instance management and user task handling, and leveraging messages/signals for event-driven communication between processes. For high-throughput scenarios, the gRPC API provides optimized job activation with streaming capabilities. The platform supports both SaaS deployment for quick adoption and Self-Managed deployment for full infrastructure control, with consistent APIs across both models.