Series MapLesson 33 / 60
Focus mode active/Press Alt+Shift+R to toggle/Esc to exit
Build CoreOrdered learning track

Workflow and REST/JAX-RS API Integration

Start process, complete task, correlate message, query process status, 202 Accepted, long-running workflow API, polling/callback/SSE patterns, error mapping, idempotency key, correlation ID, authorization, and Java/JAX-RS API contracts around Camunda.

18 min read3432 words
PrevNext
Lesson 3360 lesson track12–33 Build Core
#camunda#workflow#jax-rs#rest-api+6 more

Part 033 — Workflow and REST/JAX-RS API Integration

Goal: design REST/JAX-RS APIs around workflow orchestration without pretending that long-running business processes are synchronous CRUD operations.

A workflow API is not just an endpoint that starts Camunda. It is a contract between clients, domain state, process state, authorization, observability, and operational repair.


1. Core mental model

A REST API should expose a business command, not the workflow engine's internal mechanics.

Bad API mental model:

POST /camunda/process-definition/order-approval/start
POST /camunda/task/{taskId}/complete
POST /camunda/message/order-completed/correlate

Better API mental model:

POST /orders/{orderId}/submission
POST /quotes/{quoteId}/approval-decisions
POST /orders/{orderId}/fulfillment-callbacks
GET  /orders/{orderId}/workflow-status

The API should speak in domain language.

Camunda should remain an orchestration implementation behind the service boundary.

A client should normally not need to know:

  • Camunda process definition key;
  • process instance key;
  • task ID;
  • activity ID;
  • job key;
  • worker type;
  • internal retry count;
  • Operate/Cockpit URL;
  • BPMN element ID;
  • process variable names.

Those are implementation and diagnostic details.

The API contract should expose stable business concepts:

  • quote ID;
  • order ID;
  • customer/account ID;
  • approval decision;
  • requested action;
  • callback reference;
  • workflow status;
  • accepted/failed/rejected result;
  • correlation ID;
  • idempotency key;
  • user/action authorization.

2. Why REST-workflow integration is dangerous

A normal CRUD API usually returns after one database transaction.

A workflow API often starts a chain like this:

HTTP request
  -> validate command
  -> create/update business record
  -> start or correlate process
  -> process creates job
  -> worker calls DB/external system
  -> process waits for message/timer/user task
  -> another API completes task or correlates callback
  -> workflow eventually reaches end event

That chain can last seconds, minutes, days, or months.

So the API must not imply more certainty than the system can actually provide.

Bad response:

HTTP/1.1 200 OK

{
  "status": "ORDER_COMPLETED"
}

when the process merely started.

Better response:

HTTP/1.1 202 Accepted
Location: /orders/ORD-1001/workflow-status

{
  "orderId": "ORD-1001",
  "workflowStatus": "ACCEPTED",
  "businessStatus": "SUBMISSION_RECEIVED",
  "correlationId": "corr-93f6",
  "statusUrl": "/orders/ORD-1001/workflow-status"
}

The API must distinguish:

  • command accepted;
  • workflow started;
  • workflow completed;
  • business entity transitioned;
  • manual task pending;
  • process waiting for callback;
  • process in incident;
  • command rejected due to business rule;
  • command rejected due to duplicate/idempotency conflict.

3. REST operations around workflow

A workflow-aware backend usually exposes four categories of APIs.

3.1 Start process via API

Used when an external client or internal service asks the domain service to begin a business process.

Examples:

POST /quotes/{quoteId}/submit-for-approval
POST /orders/{orderId}/submit
POST /orders/{orderId}/cancellations
POST /orders/{orderId}/amendments

The API should usually perform:

1. authenticate caller
2. authorize command
3. validate domain preconditions
4. enforce idempotency
5. persist command acceptance/domain state
6. start process or publish outbox event to start process
7. return 202 Accepted with traceable status

3.2 Complete human task via API

Used when a user performs a workflow action.

Examples:

POST /quotes/{quoteId}/approval-decisions
POST /fallout-cases/{caseId}/resolution
POST /orders/{orderId}/manual-validation-result

The API should normally not say "complete task" to business clients.

It should expose the business action and internally map it to a user task completion or message correlation.

3.3 Correlate message via API

Used when a callback, event, or external response arrives.

Examples:

POST /orders/{orderId}/fulfillment-callbacks
POST /payments/{paymentId}/authorization-callbacks
POST /inventory/{reservationId}/reservation-results

The API should map callback metadata to:

message name + correlation key + payload + idempotency/message ID

3.4 Query process status via API

Used by clients or UIs to inspect progress.

Examples:

GET /orders/{orderId}/workflow-status
GET /quotes/{quoteId}/approval-status
GET /fallout-cases/{caseId}

The API should usually return a domain-specific projection, not raw engine state.


4. Camunda 7 vs Camunda 8 API integration mindset

4.1 Camunda 7

Camunda 7 can be embedded inside a Java application or accessed remotely through its REST API.

Common Java-side patterns:

runtimeService.startProcessInstanceByKey(
    "order_submission",
    orderId,
    variables
);
taskService.complete(taskId, variables);
runtimeService.createMessageCorrelation("FulfillmentCompleted")
    .processInstanceBusinessKey(orderId)
    .setVariables(variables)
    .correlate();

Key implication:

In Camunda 7 embedded mode, your JAX-RS endpoint and process engine can participate in the same Java application runtime, but that does not automatically make the whole business process a single safe transaction.

If the endpoint starts a process and a Java delegate performs side effects in the same transaction boundary, you must understand exactly when commit, rollback, async continuation, and job executor behavior occur.

4.2 Camunda 8 / Zeebe

Camunda 8 is typically a remote orchestration engine. A JAX-RS service sends commands to the orchestration cluster and workers later activate jobs.

Common operations:

Create process instance
Publish/correlate message
Activate/complete/fail job from worker
Query status through projection, Operate API, or application database

Key implication:

In Camunda 8, your API service and Zeebe do not share one local database transaction. You must design for command acceptance, idempotency, eventual consistency, and observable status.


5. Long-running workflow API contract

A long-running workflow API should make the lifecycle explicit.

5.1 Command accepted is not process completed

Use 202 Accepted when the command has been accepted but the process continues asynchronously.

Example:

POST /orders/ORD-1001/submission
Idempotency-Key: idem-8a31
X-Correlation-ID: corr-2026-001

Response:

HTTP/1.1 202 Accepted
Location: /orders/ORD-1001/workflow-status
{
  "orderId": "ORD-1001",
  "commandId": "cmd-7219",
  "workflowStatus": "ACCEPTED",
  "businessStatus": "SUBMISSION_RECEIVED",
  "correlationId": "corr-2026-001",
  "statusUrl": "/orders/ORD-1001/workflow-status"
}

5.2 Synchronous result is exceptional

Only use synchronous result for short-running processes with no durable side effects or where retry semantics are explicitly safe.

Dangerous pattern:

HTTP client waits until workflow finishes
  -> workflow calls external API
  -> external API is slow
  -> client timeout
  -> client retries
  -> duplicate process instance starts

Camunda 8 provides commands for asynchronous creation and creation with result. The synchronous/result style is useful for short-running processes, but if the process mutates system state, the client and service must be designed for failure and retries. Re-sending a create command can create a new process instance if idempotency is not handled by the application contract.


6. API lifecycle patterns

6.1 Start process lifecycle

sequenceDiagram participant Client participant API as JAX-RS API participant DB as PostgreSQL participant WF as Camunda participant Worker Client->>API: POST /orders/{id}/submission API->>API: Authenticate + authorize API->>DB: Validate order + record command/idempotency API->>WF: Start process / publish start command API-->>Client: 202 Accepted + status URL WF->>Worker: Create/activate job Worker->>DB: Apply domain transition Worker->>WF: Complete/fail job

Important invariant:

The API response should represent what is durable at response time.

If the order row is updated but Camunda start fails, the API must not claim the workflow started.

If Camunda starts but the DB update fails, the API must not claim the domain command was accepted unless reconciliation exists.

This is why many production systems prefer an outbox pattern for the boundary between HTTP/DB and process start.

6.2 Complete human task lifecycle

sequenceDiagram participant User participant API as Task API participant DB as Domain DB participant WF as Camunda User->>API: POST approval decision API->>API: Authenticate + authorize + validate assignment API->>DB: Persist decision audit/idempotency API->>WF: Complete task or correlate decision message API-->>User: 200/202 business response

Important invariant:

Completing a user task is a business action and must be authorized by business policy, not only by possession of a task ID.

6.3 Callback/message correlation lifecycle

sequenceDiagram participant External participant API as Callback API participant DB as Inbox/Domain DB participant WF as Camunda External->>API: POST callback API->>API: Authenticate caller / verify signature API->>DB: Store inbox event with unique key API->>WF: Publish/correlate message API-->>External: 202 Accepted / 200 Received

Important invariant:

Callback receipt and workflow correlation should be idempotent. Duplicate callbacks should not advance the process twice.


7. Business key, business ID, correlation ID, idempotency key

These identifiers are often confused.

IdentifierPurposeExampleOwner
Business key / business IDLink process instance to domain entityORD-1001Domain/service
Correlation keyRoute message to waiting process subscriptionfulfillment-request-abcIntegration contract
Correlation ID / trace IDTrace request across services/logscorr-2026-001Platform/API gateway/service
Idempotency keyDeduplicate client commandidem-8a31Client/API contract
Command IDDurable domain command identitycmd-7219Application service
Message IDDeduplicate message publication/callbackmsg-42Producer/inbox
Process instance keyEngine runtime identifier225179...Camunda

Rule:

Do not overload one ID to mean everything.

A single orderId may be a business ID, but it is not always enough as a message correlation key if the same order can have multiple concurrent interactions.

Example:

Order ORD-1001 has two concurrent waits:
  - payment authorization callback
  - inventory reservation callback

Using only ORD-1001 as the correlation key can be ambiguous.

Better:

payment correlation key   = paymentRequestId
inventory correlation key = reservationRequestId
business ID               = orderId
trace correlation ID      = HTTP/request trace ID

8. Start process via API

8.1 API design

Example:

POST /orders/{orderId}/submission
Content-Type: application/json
Idempotency-Key: idem-1001-submit
X-Correlation-ID: corr-1001
{
  "requestedBy": "user-123",
  "channel": "sales-portal",
  "submissionReason": "CUSTOMER_CONFIRMED",
  "expectedVersion": 17
}

Response:

{
  "orderId": "ORD-1001",
  "commandId": "cmd-1001-submit",
  "businessStatus": "SUBMISSION_RECEIVED",
  "workflowStatus": "START_REQUESTED",
  "statusUrl": "/orders/ORD-1001/workflow-status"
}

8.2 Validation before start

Before starting a process, validate:

  • entity exists;
  • caller can act on entity;
  • entity is in a valid state;
  • command is not stale;
  • idempotency key is not reused with a different payload;
  • no conflicting active process exists;
  • process version choice is intentional;
  • required variables are present;
  • sensitive data is not sent as process variable;
  • downstream systems are not in known disabled state, if the command depends on them.

8.3 Process version choice

Avoid implicit ambiguity.

Options:

start latest process version
start specific process version
start version selected by feature flag/config
start process through deployment-aware routing

For customer-impacting workflows, starting latest blindly can be risky during rolling deployments.

Use explicit versioning when:

  • workflow changes are not backward-compatible;
  • old and new workers run simultaneously;
  • variable schema changed;
  • message names/correlation keys changed;
  • external callbacks can arrive late;
  • regulatory/audit behavior differs by version.

8.4 Start-process failure modes

FailureSymptomConsequenceDesign response
DB accepted command, process start failedCommand exists but no process instanceStuck submissionOutbox or retry starter
Process started, DB command not recordedProcess runs with no audit rowAudit gapStart after durable command or reconcile
Client retries after timeoutDuplicate process instanceDouble approval/order actionIdempotency key + active process uniqueness
Wrong process versionUnexpected pathBusiness defectVersion routing and deployment controls
Missing required variableIncident / failed startProcess does not executeContract validation
Large variable payloadLatency/storage pressureEngine performance issueStore in DB, pass reference

9. Complete task via API

9.1 Do not expose raw task completion casually

Dangerous:

POST /tasks/{taskId}/complete

This endpoint is technically convenient but weak as a business contract.

Problems:

  • caller may complete a task they should not see;
  • task ID may leak implementation detail;
  • payload may not match expected decision schema;
  • stale UI may complete an obsolete task;
  • task may no longer belong to the quote/order state;
  • audit may only say "task completed", not "approval rejected by X because Y".

Better:

POST /quotes/{quoteId}/approval-decisions
{
  "decision": "APPROVED",
  "reasonCode": "MARGIN_EXCEPTION_ACCEPTED",
  "comment": "Approved by sales manager after exception review.",
  "expectedTaskVersion": 5
}

9.2 Authorization model

Task completion must check:

  • user identity;
  • group/role membership;
  • candidate group;
  • assignee/claim state;
  • tenant/customer boundary;
  • quote/order visibility;
  • delegation rules;
  • maker-checker rules;
  • task due/escalation state;
  • domain state compatibility.

Do not trust a Camunda task query alone as the full authorization model.

9.3 Task completion failure modes

FailureExamplePrevention
Duplicate completionUser double-clicks approveIdempotency key or decision unique constraint
Stale task UITask already escalated/cancelledexpected task version / current task validation
Unauthorized completionUser guesses task IDdomain authorization + task visibility check
Task completed but DB audit failedNo decision recordpersist decision first or transactional boundary design
DB audit committed but task completion failedDecision recorded but process stuckoutbox/manual repair/retry completion
Variables overwrite process contextCompletion sends full UI formexplicit output mapping / minimal variables

10. Correlate message via API

10.1 Message correlation is not a generic update

A message should represent something that happened outside the process.

Examples:

FulfillmentAccepted
FulfillmentRejected
PaymentAuthorized
PaymentAuthorizationFailed
InventoryReserved
InventoryReservationExpired
CustomerSignedContract

Bad message:

UpdateOrder
ContinueProcess
NextStep
Callback

Good message names tell you the business event.

10.2 Correlation contract

A callback API should define:

  • authenticated source;
  • message name;
  • correlation key field;
  • message ID/idempotency key;
  • payload schema;
  • TTL/buffering expectation;
  • duplicate policy;
  • late-arrival policy;
  • failure response semantics;
  • replay behavior;
  • audit storage.

Camunda 8 message correlation is based on subscriptions containing a message name and correlation key. A message is not sent directly to a process instance. If the process instance has not opened the relevant subscription, behavior depends on publication/correlation mode and TTL.

10.3 Callback response semantics

Do not always return 500 when a message cannot be correlated.

Possible cases:

CaseSuggested responseMeaning
Duplicate callback already processed200 OKIdempotent success
Callback accepted for async correlation202 AcceptedStored for processing
Unknown external reference404 or 202Depends on security/leakage policy
Invalid payload/signature400/401/403Reject
Message too late but known200 with ignored status or 409Business policy
Correlation temporarily unavailable202 if stored, 503 if not storedRetry policy

If you cannot durably store the callback, returning success is dangerous.

10.4 Message correlation failure modes

FailureRoot causeDebug question
Message not correlatedNo open subscriptionHas process reached catch event?
Wrong instance receives messageNon-unique correlation keyAre multiple instances waiting on same key?
Duplicate message advances twiceNo message ID/inbox dedupeIs callback idempotent?
Late message ignoredProcess left scopeIs late-arrival policy defined?
Message discardedTTL zero and no subscriptionShould buffering be enabled?
Correlated to new start instead of existing waitMessage start/catch ambiguityAre message names separated?

11. Query process status via API

11.1 Do not expose raw engine state to normal clients

A customer or business UI does not need this:

{
  "processInstanceKey": "2251799813686019",
  "elementId": "Activity_1d9xq2p",
  "jobKey": "2251799813687001"
}

It needs this:

{
  "orderId": "ORD-1001",
  "businessStatus": "IN_FULFILLMENT",
  "workflowPhase": "WAITING_FOR_FULFILLMENT_CALLBACK",
  "pendingHumanAction": false,
  "blocked": false,
  "lastUpdatedAt": "2026-07-11T08:15:00Z",
  "nextExpectedEvent": "FULFILLMENT_COMPLETED_OR_REJECTED"
}

11.2 Status projection sources

Possible sources:

SourceStrengthRisk
Domain DB status projectionStable API, business-friendlyMay lag engine unless updated correctly
Engine queryAccurate runtime stateLeaks implementation and may be expensive
Operate/CockpitGood for operatorsNot ideal as customer-facing API
Event-sourced projectionAudit-friendlyMore infrastructure complexity
CacheFastStaleness and invalidation risk

For enterprise APIs, a domain status projection is usually better than raw workflow queries.

11.3 Status state vocabulary

Define a stable external vocabulary.

Example:

NOT_STARTED
START_REQUESTED
RUNNING
WAITING_FOR_USER
WAITING_FOR_EXTERNAL_SYSTEM
BLOCKED_BY_INCIDENT
COMPLETED
CANCELLED
FAILED_REQUIRES_REPAIR

Do not expose every BPMN activity ID as a public status.

Public status should change only when meaningful to clients.


12. Polling, callback, SSE, and WebSocket

12.1 Polling

Simple and reliable.

GET /orders/{orderId}/workflow-status

Use when:

  • process duration is uncertain;
  • UI can tolerate periodic refresh;
  • infrastructure is simple;
  • status endpoint is cheap.

Risks:

  • high polling load;
  • stale UI;
  • clients polling too aggressively;
  • no push notification for urgent human task.

12.2 Callback

Use when another system must be notified.

workflow completes step -> worker publishes domain event -> subscriber/callback notified

Risks:

  • callback delivery retry;
  • receiver outage;
  • security/signature;
  • duplicate notification;
  • event ordering.

12.3 SSE/WebSocket

Useful for internal operational UI or task UI.

Risks:

  • connection lifecycle;
  • auth refresh;
  • replay after disconnect;
  • scaling across pods;
  • event fan-out;
  • consistency with persisted state.

Do not use WebSocket as the source of truth.

Use it as a notification channel on top of a durable status source.


13. Error response mapping

A workflow API must map failures carefully.

ConditionHTTP statusNotes
Invalid JSON/schema400 Bad RequestRequest is malformed
Auth missing/invalid401 UnauthorizedAuthentication failure
Caller cannot act403 ForbiddenAuthorization failure
Entity not found404 Not FoundConsider tenant leakage policy
Illegal domain transition409 ConflictState mismatch / stale command
Duplicate idempotency same payload200/202 with original resultIdempotent replay
Duplicate idempotency different payload409 ConflictKey misuse
Workflow engine unavailable after durable command stored202 Accepted if async repair existsDo not lie; expose accepted/pending
Workflow engine unavailable before durable acceptance503 Service UnavailableClient may retry
Downstream process incidentUsually 200 status query with blocked stateIncident is process state, not GET failure

Do not map every process incident to an HTTP 500.

An incident may be the current business/process state and should appear in status/projection for authorized operators.


14. JAX-RS implementation sketch: start workflow command

This is illustrative, not framework-prescriptive.

@Path("/orders/{orderId}/submission")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class OrderSubmissionResource {

  private final OrderCommandService commandService;

  @POST
  public Response submitOrder(
      @PathParam("orderId") String orderId,
      @HeaderParam("Idempotency-Key") String idempotencyKey,
      @HeaderParam("X-Correlation-ID") String correlationId,
      SubmitOrderRequest request
  ) {
    SubmitOrderResult result = commandService.submit(
        new SubmitOrderCommand(orderId, idempotencyKey, correlationId, request)
    );

    URI statusUri = URI.create("/orders/" + orderId + "/workflow-status");

    return Response.accepted(new SubmitOrderResponse(
        result.orderId(),
        result.commandId(),
        result.businessStatus(),
        result.workflowStatus(),
        statusUri.toString(),
        result.correlationId()
    ))
    .location(statusUri)
    .build();
  }
}

Command service responsibilities:

- authenticate context is already available
- authorize command
- validate entity state
- enforce idempotency
- persist command acceptance
- either start process safely or write outbox row
- return durable result

Avoid putting Camunda client calls directly in resource classes.

The resource should be thin.

Workflow integration belongs in application service/integration adapter code with tests.


15. JAX-RS implementation sketch: callback correlation

@Path("/orders/{orderId}/fulfillment-callbacks")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class FulfillmentCallbackResource {

  private final FulfillmentCallbackService callbackService;

  @POST
  public Response receiveCallback(
      @PathParam("orderId") String orderId,
      @HeaderParam("X-Callback-Signature") String signature,
      @HeaderParam("X-Correlation-ID") String correlationId,
      FulfillmentCallbackRequest request
  ) {
    CallbackReceipt receipt = callbackService.receive(
        orderId,
        signature,
        correlationId,
        request
    );

    return Response.accepted(new CallbackResponse(
        receipt.callbackId(),
        receipt.orderId(),
        receipt.receiptStatus(),
        receipt.messageCorrelationStatus()
    )).build();
  }
}

Good callback service behavior:

1. verify caller/signature
2. validate payload
3. store callback in inbox table with unique external event ID
4. decide if duplicate is idempotent replay
5. publish/correlate workflow message or enqueue outbox command
6. record correlation result
7. return receipt

16. API payload design

16.1 Start process payload

Keep start variables minimal.

Bad:

{
  "fullOrderSnapshot": { "...": "large nested object" },
  "customerPII": { "...": "sensitive" },
  "allLineItems": ["..."]
}

Better:

{
  "orderId": "ORD-1001",
  "commandId": "cmd-1001-submit",
  "requestedBy": "user-123",
  "channel": "sales-portal",
  "correlationId": "corr-1001"
}

Worker can load authoritative data from PostgreSQL using orderId.

16.2 Complete task payload

Capture decision as a business fact.

{
  "decision": "REJECTED",
  "reasonCode": "MISSING_CUSTOMER_AUTHORIZATION",
  "comment": "Customer authorization document is missing.",
  "expectedTaskVersion": 3
}

16.3 Callback payload

Capture external identity and outcome.

{
  "externalRequestId": "FUL-REQ-991",
  "externalEventId": "EVT-2026-00091",
  "outcome": "COMPLETED",
  "completedAt": "2026-07-11T08:30:00Z",
  "detailsRef": "fulfillment-system://requests/FUL-REQ-991"
}

Do not blindly copy callback payload into process variables.

Store external payload durably in an inbox/audit table and pass only required fields to the process.


17. Authorization concerns

Workflow APIs require layered authorization.

17.1 Command authorization

Can this caller request this business action?

Examples:

  • submit quote;
  • approve discount;
  • cancel order;
  • resolve fallout;
  • retry failed fulfillment;
  • manually override validation.

17.2 Entity authorization

Can this caller access this quote/order/customer/tenant?

17.3 Task authorization

Can this caller complete this specific pending task?

17.4 Operational authorization

Can this caller retry incident, migrate process, skip activity, or repair state?

Operational APIs should be separated from business APIs.

Do not expose repair operations to normal business users.


18. Observability contract

Every workflow API should emit consistent telemetry.

Required fields:

correlationId
traceId
spanId
tenantId if applicable
businessId/orderId/quoteId
commandId
idempotencyKey hash/reference
processDefinitionId/key if known
processInstanceKey/id if known
messageName if applicable
correlationKey if applicable
workflowStatus
businessStatus
caller/service/user

Metrics:

workflow_api_command_accepted_total
workflow_api_command_rejected_total
workflow_api_idempotency_replay_total
workflow_api_process_start_failure_total
workflow_api_message_correlation_failure_total
workflow_api_task_completion_failure_total
workflow_api_status_latency_ms
workflow_api_callback_duplicate_total

Logs should not expose sensitive process variables, PII, raw form data, or secrets.


19. API failure-mode debugging

19.1 Process did not start

Check:

- Was HTTP command accepted?
- Was idempotency row created?
- Was outbox row created?
- Did process start command execute?
- Which process definition/version was selected?
- Did Camunda reject variables/process ID?
- Was there a network/auth failure to engine?
- Was process created but status projection not updated?

19.2 Client got timeout and retried

Check:

- Did first request commit?
- Did second request reuse same idempotency key?
- Did API return original result or start duplicate process?
- Are there multiple active process instances for the same business ID?

19.3 Callback arrived but process did not move

Check:

- Was callback authenticated and stored?
- Was message name correct?
- Was correlation key correct?
- Had process opened subscription?
- Was message TTL appropriate?
- Was callback duplicate/late?
- Did correlation fail synchronously or async?

19.4 User task cannot complete

Check:

- Is task still active?
- Is user authorized?
- Is task assigned/claimed by someone else?
- Is entity state compatible?
- Is request stale?
- Did completion variables pass validation?
- Did Camunda completion fail after domain audit commit?

20. API anti-patterns

20.1 Exposing engine API directly

Frontend -> Camunda REST API directly

Risk:

  • authorization bypass;
  • implementation leakage;
  • unstable API contract;
  • no domain validation;
  • poor audit;
  • hard migration from Camunda 7 to 8.

20.2 Returning completed status for accepted command

Risk:

  • customer/UI believes action finished;
  • downstream failure hidden;
  • retries create duplicate business effects.

20.3 Using process instance ID as public resource ID

Risk:

  • hard migration;
  • tenant leakage;
  • debugging details become customer contract.

20.4 No idempotency key

Risk:

  • duplicate process starts;
  • duplicate approval;
  • duplicate cancellation;
  • duplicate external side effect.

20.5 Status endpoint queries engine on every request

Risk:

  • load on engine/Operate/search;
  • accidental exposure of internal state;
  • slow UI;
  • expensive polling.

20.6 Callback endpoint does not store inbox record

Risk:

  • lost callbacks;
  • no replay;
  • no duplicate detection;
  • no audit.

21. Internal verification checklist

Verify in the actual CSG/team environment.

21.1 API inventory

  • Which endpoints start workflow/processes?
  • Which endpoints complete human tasks?
  • Which endpoints receive callbacks and correlate messages?
  • Which endpoints expose workflow/process status?
  • Are any clients calling Camunda API directly?
  • Are process instance IDs/task IDs exposed externally?

21.2 JAX-RS/resource layer

  • Are Camunda client calls inside resource classes or application services?
  • Is idempotency enforced at API boundary?
  • Is correlation ID generated/propagated?
  • Is authorization domain-aware?
  • Are error responses consistent?

21.3 Start process contract

  • Is process started synchronously or asynchronously?
  • Is 202 Accepted used for long-running processes?
  • Is process version selected intentionally?
  • Is business ID/business key set?
  • Is duplicate active process prevented where required?

21.4 Task completion contract

  • Are user task actions exposed as domain actions?
  • Is task assignment/claim checked?
  • Is stale completion prevented?
  • Is decision audit persisted?
  • Are completion variables minimal and validated?

21.5 Message/callback contract

  • Are callback payloads stored durably?
  • Is duplicate callback handled?
  • Is correlation key unique enough?
  • Is late callback policy defined?
  • Is message TTL/publish/correlate behavior understood?

21.6 Status contract

  • Is there a domain-friendly status projection?
  • Does status distinguish waiting, blocked, completed, failed, manual action?
  • Is engine state hidden from normal clients?
  • Is status query efficient under polling load?
  • Are operator-only details protected?

21.7 Observability

  • Are command ID, business ID, process instance ID, correlation ID logged together?
  • Are API metrics available?
  • Are process start/correlation/task completion failures alerted?
  • Can one trace a customer order from API request to process instance to worker logs?

22. PR review checklist

Ask these questions when reviewing workflow API changes.

Contract

  • What business command does this endpoint represent?
  • Is the endpoint exposing Camunda internals unnecessarily?
  • Does the response accurately represent durable state?
  • Is 202 Accepted used when work continues asynchronously?
  • Is the public status vocabulary stable?

Correctness

  • What prevents duplicate process start?
  • What prevents stale task completion?
  • What prevents wrong message correlation?
  • What happens if the API times out after committing?
  • What happens if Camunda is unavailable?

Data

  • Are variables minimal?
  • Are PII/secrets excluded?
  • Is the domain DB the source of truth for business state?
  • Is there an inbox/outbox for external events where needed?

Security

  • Is caller authorization domain-aware?
  • Are task visibility and task action permission enforced?
  • Are operational actions separated from business actions?
  • Are tenant boundaries protected?

Operations

  • Can support find the process instance from order ID?
  • Can support find the API command from process instance?
  • Are failures observable?
  • Is manual repair possible without corrupting state?

23. Practical rule of thumb

For long-running workflow APIs:

Validate synchronously.
Accept durably.
Start or correlate idempotently.
Expose progress through stable domain status.
Keep Camunda internals behind the service boundary.

If an API cannot explain what happens after timeout, retry, duplicate callback, stale task completion, or engine outage, it is not production-ready.


24. Sources for further reading

  • Camunda 8 Docs — Process instance creation: https://docs.camunda.io/docs/components/concepts/process-instance-creation/
  • Camunda 8 Docs — Messages and correlation: https://docs.camunda.io/docs/components/concepts/messages/
  • Camunda 8 Docs — Job workers: https://docs.camunda.io/docs/components/concepts/job-workers/
  • Camunda 8 Docs — Writing good workers: https://docs.camunda.io/docs/components/best-practices/development/writing-good-workers/
  • Camunda 7 Javadocs — RuntimeService: https://docs.camunda.org/javadoc/camunda-bpm-platform/7.16/org/camunda/bpm/engine/RuntimeService.html
Lesson Recap

You just completed lesson 33 in build core. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.