The single most useful thing to understand about IBM Business Automation Workflow, if you want to build modern interfaces on top of it, is that a user task does not have to come with a user interface.
Most teams never find this out. They model a human step, BAW offers them a coach, and from that moment the process and its front end are welded together. Every screen change becomes a process-application change, which means a snapshot, a deployment, and a release window — for a label.
The mechanism that breaks the weld is the external implementation.
What it actually is
When you model a human activity, BAW asks how it is implemented. A coach is one answer. An external implementation is another: you are telling the engine that this task exists, that it should be assigned, tracked, escalated and audited exactly like any other task — but that fulfilling it happens somewhere the engine does not manage.
The engine keeps everything that makes it worth having:
- Assignment and teams. Routing to a role, a group or a team filter service still works.
- Task lifecycle. Ready, claimed, completed, released. Due dates, priority, escalation.
- Audit. Who was assigned, who claimed, when, what was submitted.
What it gives up is the screen. Your application renders that, from whatever stack you like, and reports completion back through the API.
The loop
In practice an external implementation is worked through a small, dull cycle against the Workflow REST API.
Find the work. GET /bpm/user-tasks?states=ready, filtered to the user or team in question. This is the queue your interface renders.
Claim it. POST /bpm/user-tasks/{id}/claim. This is not optional politeness — it is what stops two people working the same case, and BAW enforces it.
Fetch the data. Read the task’s business data to render the form. The shape comes from the process variables the activity exposes.
Complete it. Post the output data back and mark the task complete. The engine takes the token onward.
There is also an older family — /rest/bpm/wle/v1/*, with process start as POST /process?action=start&bpdId=… — which you will meet on traditional WAS-hosted BAW and on 8.5.7-era systems. It expresses the same ideas with different nouns.
Details that cost people a day
CSRF. The Workflow REST API expects a BPMCSRFToken header on state-changing calls. Omit it and you get a rejection whose message does not obviously say “you forgot the CSRF token.”
Authentication differs by deployment. On Cloud Pak, a Zen API key: Authorization: ZenApiKey base64(user:key). On traditional WAS-hosted BAW, basic auth or LTPA. This is the single biggest reason an integration that works in one environment fails in the next, and it is the main argument for keeping all of it behind one adapter.
Explore before you guess. There is a Swagger document at GET /bpm/docs and an explorer at /bpm/explorer. The payload shapes are more specific than the documentation implies, and reading them beats inferring them.
Why this matters beyond nicer screens
A better front end is the obvious benefit. The structural one is larger: external implementations are what make a generic human task possible.
If every human step needs its own coach, then every process needs its own model, and the number of deployable artefacts grows with the number of processes. If human steps are fulfilled externally, one modelled human activity can serve every human step of every process — the application decides which form to render based on the task type recorded in its own data.
That is the hinge on which zero-deployment workflow authoring turns. The engine contributes what it is genuinely excellent at — assignment, teams, escalation, enterprise audit — and stops being the place where interface decisions are made.
Keep it behind one seam
Whatever you build, put every BAW interaction behind a single adapter implementing a small set of contracts: start a process, list tasks, claim a task, complete a task, send a message event. No endpoint, authentication detail or payload shape should be visible anywhere else in the codebase.
Two reasons. The first is portability: the difference between a Cloud Pak container runtime and a traditional WAS deployment is almost entirely authentication and endpoint shape, and behind an adapter that is a configuration change rather than a rewrite.
The second is that you can develop without an engine at all. A fake adapter implementing the same contracts lets the whole application be built and tested before anyone has resolved which BAW environment you are targeting — which, on most enterprise programmes, takes considerably longer than the build.
What you have to build yourself
External implementations move the interface to your application, which means the parts a coach gave you for free are now yours to write. Four of them, and the last is the one teams forget.
The work list. Querying ready tasks is one call; presenting them usefully is not. Users need filtering, sorting by age and priority, and a sense of what is urgent. This is a real piece of product design, not a table.
The form. Rendering the right interface per task type. The maintainable approach is schema-driven — the task type declares its input contract and the interface renders from it — because the alternative is a bespoke component per task type and a codebase that grows linearly with the process catalogue.
Claim conflict handling. Two people open the same task; one claims it first. The second needs to be told clearly, not shown a stack trace. This is the most common rough edge in a first implementation.
Reconciliation. The one that bites. Your application holds state about tasks; the engine is authoritative. They drift — a task completed in Workplace, an admin reassignment, an instance terminated. You need a periodic reconciliation, and you need to decide explicitly that the engine wins. Teams that skip this ship something that works in testing and accumulates ghost tasks in production.
Designing the adapter contract
The seam is only worth having if it is narrow. A useful adapter is roughly six operations:
startProcess(model, businessData)— returns an instance identifierlistTasks(filter)— ready and claimed work, filtered by user or teamclaimTask(taskId, actor)completeTask(taskId, outputData, actor)releaseTask(taskId)— the one people forget until a user closes the tabsendMessage(eventName, correlationKey, payload)
If a seventh operation appears that exposes something BAW-shaped — a raw payload, an engine-specific status string — that is the signal the abstraction is leaking. The test is whether you could implement the same six against a completely different engine without changing a line of calling code.
Error taxonomy at the seam
The adapter should translate engine errors into a small set your application understands: not found, already claimed, not authorised, validation rejected, engine unavailable. Each has a different correct response, and the raw error strings differ between the legacy and current API families — which is exactly the sort of difference that should die at the seam rather than propagating into your interface code.
The fake adapter is not throwaway
Building against a local fake is usually justified as a way to work while environment access is pending. That undersells it.
A fake that implements the same six contracts — holding tasks in memory, honouring claim semantics, letting tests advance the clock — is permanently the fastest way to test everything above the seam. It runs in CI in milliseconds, needs no credentials, and lets you construct states that are tedious to reach on a real engine: a task claimed by someone else, an instance terminated mid-flight, an engine returning 503.
Teams that treat the fake as scaffolding delete it when the real environment arrives, and their test suite becomes slow, flaky and dependent on a shared server. Teams that treat it as a first-class implementation keep both, and run the same contract test suite against each. When they disagree, you have found either a bug in the fake or a real assumption you had wrong — and both are worth knowing.
EFTEDRA builds workflow automation on IBM Business Automation Workflow and Claude — assistant tasks and coach views that install into the processes you already run. See what we build, or try the live demo.

