JustFlows

Elsa Workflows · Integrate

Plugin SDK

Start Elsa workflows from your own plugin, for the current site, without handling the Elsa credentials.

Three calls

FunctionElsa APIUse it when
triggerElsaEventPOST /elsa/api/events/{eventName}/triggerSomething happened, and any workflow that cares should run. In Studio, start the workflow with an **Event** activity of the same name.
dispatchElsaWorkflowPOST /elsa/api/workflow-definitions/{id}/dispatchYou know the definition. Elsa queues it.
executeElsaWorkflowPOST /elsa/api/workflow-definitions/{id}/executeYou 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.

Inputs and results
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:

typescript
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:

typescript
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

ErrorMeaning
inactiveElsa Workflows is not active. Treat it as optional and carry on.
unboundThis site has no Elsa connection, or Elsa is turned off for the website.
invalidAn event name, definition id, correlation id, source, or input was rejected.
quotaThe site reached its monthly justflows.elsa-workflows.starts limit.
elsaElsa 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.