Workflows Explained

Understanding workflows as the core orchestration layer in bem

Workflows are the core abstraction that enables bem to power sophisticated user interfaces and business processes at scale. A workflow orchestrates multiple functions into a unified processing pipeline with a single entry point, allowing you to build complex data transformations declaratively.

What is a Workflow?

A workflow is a versioned, reusable orchestration layer that wraps one or more functions into a cohesive processing unit. Think of it as a directed graph where:

  • Nodes are functions (Transform, Route, Split, Join, Enrich, etc.)
  • Edges are relationships that define how data flows between functions
                         Workflow
+--------------------------------------------------------+
|                                                        |
|   +-----------+           +-----------+                |
|   | Transform |   ---->   |  Enrich   |                |
|   |  (main)   |           |           |                |
|   +-----------+           +-----------+                |
|                                                        |
+--------------------------------------------------------+
        ^
        |
   Input (PDF, email, JSON, etc.)

When you call a workflow, bem automatically executes all functions in the correct order, managing state and data flow between them.

Why Use Workflows?

Single Entry Point

Instead of managing multiple function calls and tracking their dependencies yourself, workflows provide a single API endpoint. Call the workflow once, and bem handles the orchestration:

curl -X POST https://api.bem.ai/v2/calls \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "calls": [{
      "workflowName": "invoice-processing",
      "input": { "singleFile": { "inputType": "pdf", "inputContent": "..." } }
    }]
  }'

Versioned Configuration

Workflows are versioned independently from the functions they contain. Each time you update a workflow's structure (changing functions or relationships), a new version is created. This means:

  • Existing integrations continue working on their version
  • You can test new workflow configurations without disrupting production
  • Rollback is straightforward—just point to a previous version

Unified Monitoring

Track the entire processing pipeline through a single workflow call. The response includes all constituent function calls, their statuses, and outputs:

{
  "call": {
    "callID": "wc_abc123",
    "callType": "workflow",
    "status": "completed",
    "workflowName": "invoice-processing",
    "functionCalls": [
      { "functionName": "invoice-extractor", "status": "completed", "transformedContent": {...} },
      { "functionName": "sku-matcher", "status": "completed", "transformedContent": {...} }
    ]
  }
}

Workflow Structure

Every workflow has two key components:

1. Main Function

The main function is the entry point—the first function that receives input when the workflow is called. It can be any function type:

{
  "name": "invoice-processing",
  "mainFunction": {
    "name": "invoice-extractor"
  }
}

2. Relationships

Relationships define how functions connect. Each relationship specifies a source function and a destination function, creating the processing graph:

{
  "relationships": [
    {
      "sourceFunction": { "name": "invoice-extractor" },
      "destinationFunction": { "name": "sku-matcher" }
    }
  ]
}

The output of the source function becomes the input for the destination function.

Common Workflow Patterns

Sequential Pipeline

Chain functions in sequence for multi-step processing:

Input --> Transform --> Enrich --> Payload Shaping

Example: Extract invoice data, match to product catalog, then format for ERP system.

{
  "name": "invoice-to-erp",
  "mainFunction": { "name": "invoice-extractor" },
  "relationships": [
    {
      "sourceFunction": { "name": "invoice-extractor" },
      "destinationFunction": { "name": "product-matcher" }
    },
    {
      "sourceFunction": { "name": "product-matcher" },
      "destinationFunction": { "name": "erp-formatter" }
    }
  ]
}

Branching with Route

Use Route functions to direct data down different paths based on classification:

                    +--> Invoice Transform
                    |
Input --> Route ----+--> Receipt Transform
                    |
                    +--> PO Transform

Example: Classify incoming documents and process each type differently.

{
  "name": "document-processor",
  "mainFunction": { "name": "document-classifier" },
  "relationships": [
    {
      "sourceFunction": { "name": "document-classifier" },
      "destinationName": "invoice",
      "destinationFunction": { "name": "invoice-extractor" }
    },
    {
      "sourceFunction": { "name": "document-classifier" },
      "destinationName": "receipt",
      "destinationFunction": { "name": "receipt-extractor" }
    },
    {
      "sourceFunction": { "name": "document-classifier" },
      "destinationName": "purchase_order",
      "destinationFunction": { "name": "po-extractor" }
    }
  ]
}

The destinationName field maps to the route names defined in your Route function configuration.

Split and Process

Handle multi-document files by splitting and processing each piece:

              +--> Doc 1 --> Transform A
              |
PDF --> Split-+--> Doc 2 --> Transform B
              |
              +--> Doc 3 --> Transform C

Example: A PDF containing multiple shipment documents, each needing extraction.

{
  "name": "shipment-bundle-processor",
  "mainFunction": { "name": "shipment-splitter" },
  "relationships": [
    {
      "sourceFunction": { "name": "shipment-splitter" },
      "destinationName": "bill_of_lading",
      "destinationFunction": { "name": "bol-extractor" }
    },
    {
      "sourceFunction": { "name": "shipment-splitter" },
      "destinationName": "commercial_invoice",
      "destinationFunction": { "name": "commercial-invoice-extractor" }
    },
    {
      "sourceFunction": { "name": "shipment-splitter" },
      "destinationName": "packing_list",
      "destinationFunction": { "name": "packing-list-extractor" }
    }
  ]
}

Aggregation with Join

Combine outputs from multiple sources into a unified result:

Source A --+
           |
Source B --+--> Join --> Unified Transform Output
           |
Source C --+

Example: Merge data from multiple related documents into a comprehensive record.

Function Reference Options

When specifying functions in workflows, you have flexibility in how you reference them:

Reference StyleExampleDescription
By name (latest version){ "name": "invoice-extractor" }Uses the current version
By ID (latest version){ "id": "f_abc123" }Uses the current version
By name with version{ "name": "invoice-extractor", "versionNum": 2 }Pins to specific version
By ID with version{ "id": "f_abc123", "versionNum": 2 }Pins to specific version

Pinning to specific versions is useful when you need deterministic behavior and want to control when updates propagate.

Creating a Workflow

curl -X POST https://api.bem.ai/v2/workflows \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "name": "invoice-processing",
    "displayName": "Invoice Processing Pipeline",
    "tags": ["finance", "invoices"],
    "mainFunction": {
      "name": "invoice-extractor"
    },
    "relationships": [
      {
        "sourceFunction": { "name": "invoice-extractor" },
        "destinationFunction": { "name": "sku-matcher" }
      }
    ]
  }'

Configuration Fields

FieldTypeRequiredDescription
namestringYesUnique identifier (alphanumeric, hyphens, underscores)
displayNamestringNoHuman-readable name for the UI
tagsstring[]NoTags for organizing workflows
mainFunctionobjectYesThe entry point function
relationshipsarrayNoFunction-to-function connections

Updating a Workflow

Updates create a new version, preserving the previous configuration:

curl -X PATCH https://api.bem.ai/v2/workflows/invoice-processing \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "mainFunction": { "name": "invoice-extractor" },
    "relationships": [
      {
        "sourceFunction": { "name": "invoice-extractor" },
        "destinationFunction": { "name": "sku-matcher" }
      },
      {
        "sourceFunction": { "name": "sku-matcher" },
        "destinationFunction": { "name": "erp-formatter" }
      }
    ]
  }'

When updating structure, you must provide both mainFunction and relationships together.

Workflow Versions

List all versions of a workflow:

curl https://api.bem.ai/v2/workflows/invoice-processing/versions \
  -H "x-api-key: YOUR_API_KEY"

Get a specific version:

curl https://api.bem.ai/v2/workflows/invoice-processing/versions/2 \
  -H "x-api-key: YOUR_API_KEY"

Executing Workflows

Call a workflow using the unified Calls API:

curl -X POST https://api.bem.ai/v2/calls \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "calls": [
      {
        "workflowName": "invoice-processing",
        "callReferenceID": "my-tracking-id-001",
        "input": {
          "singleFile": {
            "inputType": "pdf",
            "inputContent": "JVBERi0xLjQK..."
          }
        }
      }
    ]
  }'

The callReferenceID is your custom identifier for tracking this execution in your systems.

Workflows vs. Ad-hoc Function Calls

You can call functions directly without a workflow using ad-hoc calls:

curl -X POST https://api.bem.ai/v2/calls \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "calls": [
      {
        "functionName": "invoice-extractor",
        "input": { ... }
      }
    ]
  }'

When to use workflows:

  • Multiple functions need to execute in sequence
  • You need branching logic (Route functions)
  • You want unified monitoring across a pipeline
  • You're building production integrations that may evolve

When to use ad-hoc calls:

  • Single-function processing
  • Testing individual functions
  • Simple, one-off transformations

Best Practices

Start Simple, Extend Incrementally

Begin with a single-function workflow. As requirements grow, add functions and relationships:

  1. Create workflow with just a Transform function
  2. Add Enrich to augment data with your catalogs
  3. Add Payload Shaping to format for downstream systems

Use Meaningful Names

Workflow and function names should describe their purpose:

  • invoice-processing (workflow)
  • invoice-extractor (transform function)
  • product-catalog-matcher (enrich function)

Leverage Tags for Organization

Use tags to categorize workflows by domain, team, or use case:

{
  "tags": ["finance", "ap-automation", "production"]
}

Pin Versions for Stability

In production, consider pinning function versions to prevent unexpected changes:

{
  "mainFunction": { "name": "invoice-extractor", "versionNum": 3 }
}

Next Steps

On this page