Skip to main content

Quickstart — Your First Form in 15 Minutes

Prerequisites: a BPMN process with at least one userTask already registered in Stateway, and a valid API Key.

Step 1 — Create a Session in Your Backend

When a user logs into your application, add this call to your authentication handler:

// Node.js — your backend
const response = await fetch('https://api.stateway.io/v1/sessions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.STATEWAY_API_KEY,
},
body: JSON.stringify({
user_id: user.id, // id of the user in YOUR system
user_display: user.name,
ttl: 3600,
scope: {
definitions: [
{
key: 'my-process',
roles: ['operator'],
candidate_as_user: false,
can_start: true,
max_concurrent: 1
}
]
}
})
});

const { session_token } = await response.json();

// Include session_token in the login response to the frontend
// Do NOT persist the token in the backend — it is single-use by the frontend

The session_token is shown only once in the response. Forward it immediately to the frontend.

Step 2 — Install the SDK

npm install @stateway/frontend-sdk
# or
yarn add @stateway/frontend-sdk

Step 3 — Connect and Display Pending Work

import { StatewayClient } from '@stateway/frontend-sdk';

// sessionToken comes from the login response of your backend
const sw = new StatewayClient({
endpoint: 'wss://ws.stateway.io',
sessionToken: auth.statewayToken,
});

sw.on('work.snapshot', (items) => {
if (items.length === 0) return;
const task = items[0];

document.querySelector('#task-name').textContent = task.name;
document.querySelector('#task-form').innerHTML =
renderForm(task.formSchema, task.variables);
});

sw.on('work.empty', ({ definitions }) => {
const [def] = definitions.filter(d => d.canStart);
if (def) {
document.querySelector('#start-btn').style.display = 'block';
document.querySelector('#start-btn').onclick = () =>
sw.startProcess(def.key);
}
});

work.snapshot fires immediately after connect with all tasks the user currently has pending. work.empty fires when there is no pending work but the user may start new instances.

Step 4 — Complete the Task

document.querySelector('#submit-btn').onclick = async () => {
const formData = getFormData();
await sw.completeTask(currentTaskId, formData);
// The next state arrives automatically via work.snapshot or task.assigned
};

The SDK handles reconnection automatically. If the connection drops, it reconnects with exponential backoff (1s → 2s → 4s → 30s max) and re-delivers any missed events.

Next Steps