Elsa Workflows · Integrate
Plugin SDK
Start Elsa workflows from your own plugin, for the current site, without handling the Elsa credentials.
Three calls
| Function | Elsa API | Use it when |
|---|---|---|
triggerElsaEvent | POST /elsa/api/events/{eventName}/trigger | Something happened, and any workflow that cares should run. In Studio, start the workflow with an **Event** activity of the same name. |
dispatchElsaWorkflow | POST /elsa/api/workflow-definitions/{id}/dispatch | You know the definition. Elsa queues it. |
executeElsaWorkflow | POST /elsa/api/workflow-definitions/{id}/execute | You know the definition and want to wait until Elsa accepts the instance. |
Each call runs for the current site, against that site’s Elsa server and tenant. Your plugin never sees the address or the credentials.
type ElsaEventTrigger = {
eventName: string; // The name of the Event activity in Studio
input?: Record<string, unknown>; // At most 16 KB
correlationId?: string; // 1–128 of A–Z a–z 0–9 . _ : -
source?: string; // Your plugin id for the audit log: lowercase, digits, . and -. Defaults to "plugin"
};
type ElsaWorkflowRun = {
definitionId: string; // 1–80 of A–Z a–z 0–9 _ -
input?: Record<string, unknown>;
correlationId?: string;
source?: string;
};
type ElsaSdkResult =
| { ok: true; instanceIds: string[]; correlationId: string }
| { ok: false; error: "inactive" | "unbound" | "invalid" | "quota" | "elsa" };Call it from your plugin
A plugin built in the same workspace imports the SDK:
import { triggerElsaEvent } from "justflows.elsa-workflows/sdk";
const result = await triggerElsaEvent({
eventName: "acme.booking.confirmed",
correlationId: bookingId,
source: "acme.bookings",
input: { bookingId, guests: 2 },
});
if (!result.ok && result.error !== "inactive" && result.error !== "unbound") {
ctx.logger.warn("Elsa workflow was not started", { error: result.error });
}A plugin installed as its own package cannot resolve that import. Once Elsa Workflows has loaded, it reads the same functions from a global symbol:
type ElsaSdk = typeof import("justflows.elsa-workflows/sdk");
const elsa = (globalThis as Record<symbol, unknown>)[Symbol.for("justflows.elsa-workflows.sdk")] as
| Pick<ElsaSdk, "triggerElsaEvent" | "dispatchElsaWorkflow" | "executeElsaWorkflow">
| undefined;
await elsa?.dispatchElsaWorkflow({
definitionId: "booking-follow-up",
correlationId: bookingId,
source: "acme.bookings",
input: { bookingId },
});Errors
| Error | Meaning |
|---|---|
inactive | Elsa Workflows is not active. Treat it as optional and carry on. |
unbound | This site has no Elsa connection, or Elsa is turned off for the website. |
invalid | An event name, definition id, correlation id, source, or input was rejected. |
quota | The site reached its monthly justflows.elsa-workflows.starts limit. |
elsa | Elsa refused the call or could not be reached. |
The calls never throw for these cases, so a missing or unreachable Elsa never breaks your request. Call them after your own data is saved, and keep slow work off the visitor’s response.
Limits
- Input is a JSON object of at most 16 KB, 8 levels deep, with at most 50 keys per object and strings of at most 2,000 characters.
- Event names start with a letter and use up to 160 letters, digits, and
. _ : -, so you can reuse your own hook names. - Each successful call counts as one start toward the site’s monthly limit.
- The input is sent to Elsa and is not stored by Justflows, not written to the audit log, and not included in the hooks.