Architecture: the assistant handles the conversation and calls a small integration service (a custom extension / webhook implemented as a microservice) that talks to BAW's REST API as the chatting user. Never give the bot administrator credentials - map the chat identity to the BAW user (single sign-on, or a service account with an explicit "on behalf of" user parameter and strict allow-list).
# 1. start a process (leave request) - service account with the chatting user as parameter; BAW 21+ / CP4BA
POST /bpm/processes?bpdId=25.abc...&snapshotId=2064.def...¶ms={"request":{"employee":"jane","from":"2025-07-01","to":"2025-07-05","type":"VACATION"}}
Authorization: ZenApiKey <base64(user:apikey)> (traditional BAW: Basic auth + BPMCSRFToken)
-> { "piid": "2072.900", "name": "Leave request LR-1234" }
# 2. list the user's tasks (manager asks "what do I need to approve?")
GET /bpm/user-tasks?filter=status%20eq%20%27Received%27%20and%20assignedUser%20eq%20%27mark%27&pageSize=10
# 3. complete a task from the chat ("approve LR-1234")
PUT /bpm/user-tasks/2078.911?action=complete¶ms={"decision":"APPROVED","comment":"approved via chat"}// integration microservice (Node.js) used as a custom extension of the assistant - one function per intent
app.post('/leave/start', async (req, res) => {
const { user, from, to, type } = req.body; // user comes from the assistant's authenticated context
const r = await baw.post(`/bpm/processes?bpdId=${BPD}&snapshotId=${SNAP}¶ms=${encodeURIComponent(JSON.stringify({ request: { employee: user, from, to, type } }))}`);
res.json({ instance: r.data.name });
});
app.post('/tasks/complete', async (req, res) => {
const { user, taskId, decision } = req.body;
const t = await baw.get(`/bpm/user-tasks/${taskId}`); // authorisation check: the task must be assigned to this user / their team
if (t.data.assignedUser !== user && !t.data.assignedTeamMembers?.includes(user)) return res.status(403).json({ error: 'not your task' });
await baw.put(`/bpm/user-tasks/${taskId}?action=complete¶ms=${encodeURIComponent(JSON.stringify({ decision }))}`);
res.json({ ok: true });
});Design rules: the process stays the source of truth (the bot only starts, reads and completes; rules and approvals live in the BPD); keep chat-completable tasks simple (yes / no with a comment) and leave complex forms to Workplace with a deep link the bot sends; confirm actions before executing them ("Approve LR-1234 for Jane, 5 days? yes / no"); log every action with the chat user; and use the OpenAPI document of your integration service also for watsonx Orchestrate skills (question on Orchestrate) so that both channels share one implementation. The bot's answers about status ("where is my request?") come from the instance's data and the current task's assignee - expose them through a read-only endpoint of the integration service.
References