Last Updated: April 2026
A Spring Boot application that provides REST and SOAP API endpoints for interacting with Camunda 8 SaaS Orchestration Cluster using the official Camunda Java Client. It exposes endpoints for topology retrieval, decision definition lookup, decision definition search, and DMN evaluation.
- Overview
- Tech Stack
- Project Structure
- Prerequisites
- Configuration
- Running the Application
- Swagger UI / OpenAPI Docs
- REST API Endpoints
- SOAP Endpoint
- Request & Response Models
- Running Tests
- Building a JAR
- Troubleshooting
- Contributing
- License
This application acts as a Java-based REST and SOAP proxy for Camunda 8 Orchestration APIs. It is useful for:
- Retrieving cluster topology and decision definitions.
- Searching deployed DMN decision definitions with paging/filter criteria.
- Evaluating decision definitions (DMN) with input variables.
- Exposing SOAP/WSDL interfaces for enterprise integrations.
- Serving as a reference implementation of
camunda-client-javain Spring Boot.
| Technology | Version |
|---|---|
| Java | 21 |
| Spring Boot | 4.0.5 |
| Spring Web MVC | via spring-boot-starter-web |
| Spring Web Services (SOAP) | via spring-boot-starter-web-services |
| Bean Validation | via spring-boot-starter-validation |
| Camunda Java Client | 8.9.0 |
| OpenAPI + Swagger UI | springdoc-openapi-starter-webmvc-ui:3.0.2 |
| JAXB | jakarta.xml.bind-api, jaxb-runtime |
| WSDL support | io.github.librewsdl4j:libre-wsdl4j:1.12.0 |
| Maven | 3.x (via wrapper mvnw) |
src/
├── main/
│ ├── java/org/camunda/community/api/
│ │ ├── OrchestrationApiClientApplication.java
│ │ ├── CamundaClientConfiguration.java
│ │ ├── DecisionEvaluationService.java
│ │ ├── DecisionDTO.java
│ │ ├── OpenApiConfig.java
│ │ ├── rest/
│ │ │ └── DecisionDefinitionController.java
│ │ └── soap/
│ │ ├── SoapWebServiceConfig.java
│ │ ├── DecisionEvaluationSoapEndpoint.java
│ │ ├── SoapUtils.java
│ │ └── model/
│ │ ├── EvaluateDecisionRequest.java
│ │ ├── EvaluateDecisionResponse.java
│ │ ├── SoapDecisionVariables.java
│ │ └── SoapVariableEntry.java
│ └── resources/
│ ├── application.yaml
│ └── decision-evaluation.xsd
└── test/
└── java/org/camunda/community/api/
├── OrchestrationApiClientApplicationTests.java
├── rest/DecisionDefinitionControllerTest.java
└── soap/
├── EvaluateDecisionRequestJaxbTest.java
├── SoapUtilsTest.java
├── DecisionEvaluationSoapEndpointTest.java
└── DecisionEvaluationSoapEndpointContractTest.java
- Java 21+
- Maven 3.x (or use
./mvnw) - Camunda 8 SaaS cluster credentials:
- Cluster ID
- Cluster Region
- OAuth Client ID
- OAuth Client Secret
Set the following variables before starting the app:
| Environment Variable | Description |
|---|---|
CAMUNDA_CLUSTER_ID |
Camunda SaaS cluster UUID |
CAMUNDA_CLUSTER_REGION |
Cluster region (for example cle-1) |
CAMUNDA_CLIENT_ID |
OAuth M2M client ID |
CAMUNDA_CLIENT_SECRET |
OAuth M2M client secret |
These map to src/main/resources/application.yaml:
camunda:
cluster:
id: ${CAMUNDA_CLUSTER_ID}
region: ${CAMUNDA_CLUSTER_REGION}
client:
id: ${CAMUNDA_CLIENT_ID}
secret: ${CAMUNDA_CLIENT_SECRET}Allow outbound access to:
- Zeebe endpoint:
{CAMUNDA_CLUSTER_ID}.{CAMUNDA_CLUSTER_REGION}.zeebe.camunda.io:443 - OAuth endpoint:
https://login.cloud.camunda.io/oauth/token
export CAMUNDA_CLUSTER_ID=your-cluster-id
export CAMUNDA_CLUSTER_REGION=your-cluster-region
export CAMUNDA_CLIENT_ID=your-client-id
export CAMUNDA_CLIENT_SECRET=your-client-secret$env:CAMUNDA_CLUSTER_ID = "your-cluster-id"
$env:CAMUNDA_CLUSTER_REGION = "your-cluster-region"
$env:CAMUNDA_CLIENT_ID = "your-client-id"
$env:CAMUNDA_CLIENT_SECRET = "your-client-secret"brew install direnv
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrcCreate .envrc in the project root with your values, then allow it:
direnv allow ../mvnw clean spring-boot:runThe app runs on http://localhost:8080.
When the app is running:
http://localhost:8080/swagger-ui/index.htmlhttp://localhost:8080/swagger-ui.htmlhttp://localhost:8080/v3/api-docshttp://localhost:8080/v3/api-docs.yaml
All REST endpoints are available under the /api/camunda prefix.
GET /api/camunda/topology
Returns Camunda cluster topology information.
GET /api/camunda/decision-definitions/{decisionDefinitionKey}
| Path Parameter | Description |
|---|---|
decisionDefinitionKey |
Camunda decision definition key |
GET /api/camunda/decision-definitions/{decisionDefinitionKey}/xml
| Path Parameter | Description |
|---|---|
decisionDefinitionKey |
Camunda decision definition key |
POST /api/camunda/decision-definitions/search
Content-Type: application/json
The current implementation applies these request fields:
page.frompage.limitfilter.decisionDefinitionIdfilter.namefilter.decisionDefinitionKey
sort and other filter fields may be accepted in payloads but are not currently applied by DecisionEvaluationService.
Example request:
{
"page": {
"from": 0,
"limit": 100
},
"sort": [
{
"field": "decisionDefinitionKey",
"order": "ASC"
}
],
"filter": {
"decisionDefinitionId": "new-hire-onboarding-workflow",
"name": "string",
"decisionDefinitionKey": "2251799813326547"
}
}POST /api/camunda/decision-definitions/evaluation
Content-Type: application/json
Rules enforced by the current implementation:
- Either
decisionDefinitionIdordecisionDefinitionKeyis required. - If both are present,
decisionDefinitionIdtakes priority. - If only
decisionDefinitionKeyis present:- Numeric value -> evaluated as a Camunda decision key (
long). - Non-numeric value -> treated as a decision ID fallback.
- Numeric value -> evaluated as a Camunda decision key (
Request example using decisionDefinitionId:
{
"decisionDefinitionId": "my-decision-id",
"variables": {}
}Request example using decisionDefinitionKey:
{
"decisionDefinitionKey": "2251799813326547",
"variables": {}
}SOAP endpoint path: /ws/*
http://localhost:8080/ws/decisionEvaluation.wsdl
The SOAP operation is evaluateDecisionRequest in namespace http://camunda.org/consulting/decision-evaluation.
Request example using decisionDefinitionId:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:dec="http://camunda.org/consulting/decision-evaluation">
<soapenv:Header/>
<soapenv:Body>
<dec:evaluateDecisionRequest>
<dec:decisionDefinitionId>myDecisionId</dec:decisionDefinitionId>
<dec:variables>
<dec:entry>
<dec:key>team</dec:key>
<dec:value>East Regional</dec:value>
</dec:entry>
<dec:entry>
<dec:key>state</dec:key>
<dec:value>Alabama</dec:value>
</dec:entry>
</dec:variables>
</dec:evaluateDecisionRequest>
</soapenv:Body>
</soapenv:Envelope>Complex nested object request example:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:dec="http://camunda.org/consulting/decision-evaluation">
<soapenv:Header/>
<soapenv:Body>
<dec:evaluateDecisionRequest>
<dec:decisionDefinitionId>discount-decision</dec:decisionDefinitionId>
<dec:variables>
<dec:entry>
<dec:key>order</dec:key>
<dec:value>
<dec:customerType>VIP</dec:customerType>
<dec:total>1000</dec:total>
<dec:items>
<dec:category>ELECTRONICS</dec:category>
<dec:quantity>1</dec:quantity>
</dec:items>
<dec:items>
<dec:category>ELECTRONICS</dec:category>
<dec:quantity>1</dec:quantity>
</dec:items>
</dec:value>
</dec:entry>
</dec:variables>
</dec:evaluateDecisionRequest>
</soapenv:Body>
</soapenv:Envelope>Note: repeated sibling elements (for example multiple <dec:items>) are normalized into Java lists by backend SOAP value normalization.
Both decisionDefinitionId and decisionDefinitionKey are optional at schema level, but the service requires at least one.
Success response (example with object-like result payload):
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<ns2:evaluateDecisionResponse xmlns:ns2="http://camunda.org/consulting/decision-evaluation">
<ns2:success>true</ns2:success>
<ns2:result>
<outcome>approved</outcome>
</ns2:result>
</ns2:evaluateDecisionResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>Success Response (detailed decision output):
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns2:evaluateDecisionResponse xmlns:ns2="http://camunda.org/consulting/decision-evaluation">
<ns2:success>true</ns2:success>
<ns2:result>
<decisionEvaluationKey>6755399444437420</decisionEvaluationKey>
<decisionId>discount-decision</decisionId>
<decisionInstanceKey>6755399444437420</decisionInstanceKey>
<decisionKey>2251799816375669</decisionKey>
<decisionName>Discount Decision</decisionName>
<decisionOutput>0.15</decisionOutput>
<decisionRequirementsId>discount-decision-DRD</decisionRequirementsId>
<decisionRequirementsKey>2251799816375667</decisionRequirementsKey>
<decisionVersion>11</decisionVersion>
<evaluatedDecisions>
<item>
<decisionEvaluationInstanceKey>6755399444437420-1</decisionEvaluationInstanceKey>
<decisionId>discount-decision</decisionId>
<decisionKey>2251799816375669</decisionKey>
<decisionName>Discount Decision</decisionName>
<decisionOutput>0.15</decisionOutput>
<decisionType>DECISION_TABLE</decisionType>
<decisionVersion>11</decisionVersion>
<evaluatedInputs>
<item>
<inputId>Input_1</inputId>
<inputName>Customer Type</inputName>
<inputValue>"VIP"</inputValue>
</item>
<item>
<inputId>InputClause_1ip3z40</inputId>
<inputName>Total Amount</inputName>
<inputValue>1000</inputValue>
</item>
<item>
<inputId>InputClause_1nqicll</inputId>
<inputName>Electronics Category Count</inputName>
<inputValue>true</inputValue>
</item>
</evaluatedInputs>
<matchedRules>
<item>
<evaluatedOutputs>
<item>
<outputId>Output_1</outputId>
<outputName>Discount</outputName>
<outputValue>0.15</outputValue>
</item>
</evaluatedOutputs>
<ruleId>DecisionRule_16s0n6q</ruleId>
<ruleIndex>1</ruleIndex>
</item>
</matchedRules>
<tenantId><default></tenantId>
</item>
</evaluatedDecisions>
<failedDecisionId></failedDecisionId>
<failureMessage></failureMessage>
<tenantId><default></tenantId>
</ns2:result>
</ns2:evaluateDecisionResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>Note: repeated XML nodes in decision output (for example <item> under evaluatedInputs or matchedRules) map to list-like structures during normalization.
Success response (example with scalar result field):
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<ns2:evaluateDecisionResponse xmlns:ns2="http://camunda.org/consulting/decision-evaluation">
<ns2:success>true</ns2:success>
<ns2:result>
<decision>approved</decision>
</ns2:result>
</ns2:evaluateDecisionResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>Error response (business validation/service error):
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<ns2:evaluateDecisionResponse xmlns:ns2="http://camunda.org/consulting/decision-evaluation">
<ns2:success>false</ns2:success>
<ns2:errorMessage>Either decisionDefinitionId or decisionDefinitionKey must be provided.</ns2:errorMessage>
</ns2:evaluateDecisionResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>DecisionEvaluationSoapEndpoint returns business errors in the response payload (success=false) instead of emitting a SOAP Fault.
{
"decisionDefinitionId": "string",
"decisionDefinitionKey": "string",
"variables": {
"firstInputKey": "firstInputValue",
"secondInputKey": "secondInputValue"
}
}variables is represented as Map<String, Object>.
decision-evaluation.xsd defines:
evaluateDecisionRequestevaluateDecisionResponseSoapDecisionVariableswith repeatedentrySoapVariableEntry(key+value, wherevalueisxsd:anyType)
Run all tests:
./mvnw testRun specific tests:
./mvnw test -Dtest=DecisionDefinitionControllerTest
./mvnw test -Dtest=DecisionEvaluationSoapEndpointTest
./mvnw test -Dtest=DecisionEvaluationSoapEndpointContractTest
./mvnw test -Dtest=EvaluateDecisionRequestJaxbTest
./mvnw test -Dtest=SoapUtilsTest
./mvnw test -Dtest=OrchestrationApiClientApplicationTests./mvnw clean packageArtifact:
target/orchestration-api-client-java-0.0.1-SNAPSHOT.jar
Run it:
java -jar target/orchestration-api-client-java-0.0.1-SNAPSHOT.jarIf startup fails with unresolved placeholders, make sure all four Camunda environment variables are set.
- Confirm app is running on port
8080. - Verify
http://localhost:8080/v3/api-docsreturns JSON.
- Confirm app is running.
- Verify
http://localhost:8080/ws/decisionEvaluation.wsdl. - Check logs for SOAP configuration issues.
- Fork the repository.
- Create a branch:
git checkout -b feature/my-feature - Commit:
git commit -m 'Add my feature' - Push:
git push origin feature/my-feature - Open a pull request.
This project is licensed under the Apache License, Version 2.0. See LICENSE for details.