Skip to main content
Branching allows an action to direct the flow to one of several downstream paths based on the outcome of its perform function. This is useful for routing logic like “if the record already exists, update it; otherwise, create it.”

Enabling branching on an action

Set allowsBranching: true on the action definition. The perform function must then return an ActionPerformBranchingDataReturn, which extends the standard return with a required branch field:
interface ActionPerformBranchingDataReturn<ReturnData>
  extends ActionPerformDataReturn<ReturnData> {
  /** The name of the branch to take. */
  branch: string;
}

Static branches

Use staticBranchNames when the set of possible branches is known at component-authoring time. The branch value returned by perform must exactly match one of the names in staticBranchNames:
import { action, input } from "@prismatic-io/spectral";

export const upsertContact = action({
  display: {
    label: "Upsert Contact",
    description: "Create or update a contact, then branch based on which occurred",
  },
  inputs: {
    connection: input({ label: "Connection", type: "connection", required: true }),
    email: input({
      label: "Email Address",
      type: "string",
      required: true,
    }),
    name: input({
      label: "Full Name",
      type: "string",
      required: true,
    }),
  },
  allowsBranching: true,
  staticBranchNames: ["Created", "Updated"],
  perform: async (context, params) => {
    const { connection, email, name } = params;
    const apiKey = connection.fields.apiKey as string;

    // Check if the contact exists
    const searchResponse = await fetch(
      `https://api.example.com/contacts?email=${encodeURIComponent(email)}`,
      { headers: { Authorization: `Bearer ${apiKey}` } }
    );
    const searchResult = await searchResponse.json();

    if (searchResult.contacts.length > 0) {
      // Contact exists — update it
      const existing = searchResult.contacts[0];
      const updateResponse = await fetch(
        `https://api.example.com/contacts/${existing.id}`,
        {
          method: "PATCH",
          headers: {
            Authorization: `Bearer ${apiKey}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ name }),
        }
      );
      const updated = await updateResponse.json();

      return { data: updated, branch: "Updated" };
    } else {
      // Contact does not exist — create it
      const createResponse = await fetch("https://api.example.com/contacts", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${apiKey}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ email, name }),
      });
      const created = await createResponse.json();

      return { data: created, branch: "Created" };
    }
  },
  examplePayload: {
    data: { id: "cnt_01HXYZ", email: "alice@example.com", name: "Alice Smith" },
    branch: "Created",
  },
});

Dynamic branches

Use dynamicBranchInput when the set of branches is not known at authoring time — for example, when they are driven by user configuration. Set dynamicBranchInput to the key of an input whose value at runtime contains the branch name to take.
When using dynamicBranchInput, omit staticBranchNames. The Prismatic UI will read the selected value from the specified input field to determine which branch to draw.
import { action, input } from "@prismatic-io/spectral";

export const routeByStatus = action({
  display: {
    label: "Route by Order Status",
    description: "Branch based on the status of an order",
  },
  inputs: {
    connection: input({ label: "Connection", type: "connection", required: true }),
    orderId: input({
      label: "Order ID",
      type: "string",
      required: true,
    }),
    // The integration builder configures the branch name in this input
    branchName: input({
      label: "Branch Name",
      type: "string",
      comments: "The value of this field determines which branch is taken",
    }),
  },
  allowsBranching: true,
  dynamicBranchInput: "branchName", // Key of the input that holds the branch name
  perform: async (context, params) => {
    const { connection, orderId } = params;
    const apiKey = connection.fields.apiKey as string;

    const response = await fetch(
      `https://api.example.com/orders/${orderId}`,
      { headers: { Authorization: `Bearer ${apiKey}` } }
    );
    const order = await response.json();

    // The branch name is taken from the dynamicBranchInput at runtime
    return { data: order, branch: order.status };
  },
});

Branching in triggers

Triggers support the same branching fields as actions: allowsBranching, staticBranchNames, and dynamicBranchInput. When a trigger branches, it uses TriggerBranchingResult:
interface TriggerBranchingResult<TPayload> extends TriggerBaseResult<TPayload> {
  branch: string;
}
import { trigger } from "@prismatic-io/spectral";

export const eventTypeTrigger = trigger({
  display: {
    label: "Webhook — Branch by Event Type",
    description: "Routes webhook payloads based on the event type field",
  },
  inputs: {},
  scheduleSupport: "invalid",
  synchronousResponseSupport: "valid",
  allowsBranching: true,
  staticBranchNames: ["contact.created", "contact.updated", "contact.deleted"],
  perform: async (context, payload, params) => {
    const eventType = payload.body.data?.event as string;

    if (!eventType) {
      throw new Error("Missing event type in webhook payload");
    }

    return { payload, branch: eventType };
  },
});

How branches work in the integration builder

When an action has allowsBranching: true, the Prismatic integration builder renders branch handles on the step. Each branch becomes a separate downstream path:
  • Static branches (staticBranchNames): The UI shows one labeled handle per name in the array. The handles appear as soon as the step is added to the flow.
  • Dynamic branches (dynamicBranchInput): The UI reads the value of the specified input at design time to determine which handles to draw. The integration builder provides the branch names by configuring the designated input.
The string returned in branch at runtime must exactly match one of the branch handles configured in the integration. If it does not match, the execution will fail.