Skip to main content
A customer reports that checkout failed. Your API log shows a 500, but it doesn’t tell you whether stock was reserved, payment was retried, or shipping caused the failure. In this tutorial, we’ll expose the checkout from Getting Started through an Express REST endpoint and attach Siglo’s live monitor. We’ll send real HTTP requests, inspect the named steps, and compare a successful checkout with a failed one. The demo runs locally with fake inventory, payment, and shipping services. The API listens on port 3000, and the monitoring dashboard listens on 4000. Both run in the same Node.js process and share an event emitter.

1. How the Pieces Fit Together

The REST adapter maps HTTP input to workflow context and workflow output to an HTTP response. The monitor observes execution events. Monitoring doesn’t create the business endpoint or start a workflow by itself; we connect the two explicitly.

2. Install and Start

If you followed the previous tutorial, keep checkout.ts and checkout-demo.ts in the same directory. The first exports createCheckout; the second exports fake services for this local demo. Install the additional dependencies:
This assumes the Node.js and TypeScript setup from Getting Started. The server code below uses that tutorial’s CommonJS setup. Running from this repository? The complete example is already in examples/src/getting-started. With repository dependencies installed, run these commands from the repository root:
The monitor serves its packaged dashboard. If you are developing the dashboard itself, build its UI assets before rebuilding the monitor package.

3. Connect the Endpoint to the Monitor

Create checkout-server.ts alongside the other two files:
For the standalone tutorial project, start it with:
The key connections are:
  • createMonitorServer(...) starts one monitor at application startup.
  • .monitor(monitor.emitter) sends this checkout’s events to that monitor.
  • sigloExpressMiddleware(checkout, ...) executes the checkout for the HTTP request.
  • input selects business fields; output returns a small public response instead of the full workflow context.
  • namespace: 'checkout-demo' groups these executions in the monitor.
Validation happens before workflow execution. Missing fields and invalid quantities return 400 without reserving stock or recording a workflow run. The workflow retains its own validation too, so callers outside HTTP still get those checks. A fresh set of fake services is created for each request so the demo’s payment-attempt counter belongs to that checkout. In a real application, inject reusable service clients without sharing mutable request state.

4. Send a Successful Request

Open http://127.0.0.1:4000 in your browser before sending the request. In another terminal, run:
The response has status 201 Created, echoes X-Correlation-Id, and includes an X-Workflow-Stack-Id header. Its JSON body is:
The fake gateway rejects the first payment attempt before accepting a charge, then succeeds on retry. The server console shows:
The HTTP request waits for the workflow to complete; this endpoint doesn’t enqueue a background job. The adapter’s five-second timeout bounds workflow execution. Real service clients should also support cancellation and their own request deadlines; see Timeouts and Cancellation.

5. Inspect the Execution

Select the new execution in the dashboard. Use its stack ID from the response header to identify the exact run. If it hasn’t appeared, click Refresh workflows in the top-right corner. The demo is fast, so you may see the completed run rather than watching each transition as it happens. Its recorded events still show the retry. These screenshots show the dashboard running the local checkout demo. Your execution IDs and timings will differ. In Topology (DAG), select chargePayment to inspect its two attempts. The run is COMPLETED; the payment error shown in the step details belongs to the first attempt, before the retry succeeded. Siglo live monitor showing a completed checkout, its four workflow steps, and chargePayment details with two attempts Switch to Latency Waterfall to compare the recorded step timings. Siglo latency waterfall showing the successful checkout’s four steps and their durations Open Context & State Diff to inspect the completed checkout’s state, including reservationId, paymentId, and trackingId. Siglo context viewer showing order-1001 and the reservation, payment, and tracking IDs from the successful checkout You can also inspect executions without the browser:
Replace STACK_ID with the X-Workflow-Stack-Id from the successful response:
The detail response contains the run status, steps, context changes, and events. The namespace is a grouping/filtering value in this demo, not an authentication boundary.

Subscribe to Live Events

In a separate terminal, start the SSE stream before sending another checkout:
Now send another request. You’ll receive events such as flow:start, step:start, step:retry, step:complete, and flow:complete. This stream shows new events; use the workflow detail API for recorded execution history. Press Ctrl+C to disconnect.

Read Metrics

The output includes siglo_flow_executions_total and siglo_step_retries_total. These counters belong to this monitor instance and reset when it restarts. For scraping and dashboards, continue with Prometheus and Grafana.

6. Trigger a Shipping Failure

The demo-only failShipping=true query flag simulates a courier rejecting the shipment after payment succeeds:
The endpoint returns 500 with:
exposeErrorDetails: false keeps internal workflow error messages out of this response. Select the failed run in the monitor to inspect the shipping failure. The server console shows the business cleanup:
Refresh the dashboard if needed, select the FAILED execution, and click arrangeShipping in Topology (DAG). Its step details show the internal error, No courier available, while the public HTTP response above stays generic. Siglo live monitor showing a failed checkout with arrangeShipping selected and the No courier available error Refunding payment and releasing stock doesn’t turn the checkout into a successful order. The workflow remains failed because delivery was never arranged. See Compensation and Sagas for handling failed compensation operations as well. Try changing quantity to 0: that request returns 400 at the HTTP boundary and doesn’t add a workflow run.

7. Verify the Integration

The HTTP integration test starts both servers on available ports and exercises the real endpoint. From the repository root, after building the packages, run:
It checks the response body and stack header, recorded retry, failed-run status, rejection of invalid input, exclusion of arbitrary secret fields, metrics, and dashboard HTML delivery. The checkout tests verify the actual compensation order.

8. Take It Beyond the Local Demo

For a production endpoint, replace the fake clients, remove the failure flag, derive prices from trusted order records, and authenticate callers before running the workflow. Select a namespace from trusted application identity when serving multiple tenants. This endpoint executes each accepted request as a new workflow run. The correlation header helps trace a request; it doesn’t deduplicate it. Add workflow idempotency and provider-side payment keys using the checkout idempotency walkthrough. For custom execution options beyond the Express adapter’s interface, call checkout.run(input, options) from your route and map the response explicitly. The monitor binds to loopback here, keeps execution history in memory, and disables interactive resume/replay with allowRemoteResume: false. Before making it remotely accessible, configure authentication and telemetry redaction using the monitor deployment guide. Business-field allowlisting reduces accidental data collection, but real provider results also need review for sensitive fields. To observe workers in another process, attach a remote monitor client instead of sharing an in-process emitter. For long-running work that should outlive an HTTP request, use a queue worker or a durable workflow with persistent storage and a defined status/resumption API. Press Ctrl+C in the server terminal to close the API and monitor together. Continue with Run Checkout Across Two Servers with PostgreSQL and Redis for shared checkpoints, cross-instance request deduplication, Redis caching, and a separate live monitor, with a complete Docker Compose setup.