# How to Build

### Overview

Laminar workflows allow you to create sequences of API operations with data transformations. Each workflow consists of multiple flows that execute in order, with the ability to pass data between them using the Global Workflow Object.

### Key Components

#### 1. Configuration Store

The configuration store manages reusable properties and credentials:

* Store properties referenced via `{{props.propertyName}}`
* Manage authentication credentials for flows
* Create environment-specific configurations (dev/staging/prod)

Example configuration store:

```json
{
  "name": "Production Store",
  "workspaceId": 123,
  "properties": [
    {
      "key": "apiVersion",
      "value": "2.1"
    },
    {
      "key": "baseUrl", 
      "value": "https://api.store.com"
    }
  ],
  "flowCredentialPairs": [
    {
      "flowId": 456,
      "sourceAuthCredentialId": 789,
      "destinationAuthCredentialId": 101
    }
  ]
}
```

#### 2. Flow Programs

Flow programs are JavaScript/TypeScript functions that:

* Receive payloads with input data and previous step results
* Make HTTP requests using `lam.httpRequest` or `lam.httpRequests`
* Transform data between steps
* Control workflow execution using keywords

Example flow program:

```javascript
(payload) => {
  const { input } = payload;
  
  const httpDestination = {
    "method": "POST",
    "url": "{{props.baseUrl}}/orders/{{orderId}}/items",
    "pathParams": {
      "orderId": input.orderId
    },
    "headers": {
      "Content-Type": "application/json",
      "X-Api-Version": "{{props.apiVersion}}"
    },
    "body": {
      "quantity": input.quantity,
      "notes": input.notes
    }
  };

  return {
    "lam.httpRequest": httpDestination
  };
}
```

### Advanced Features

#### Parallel HTTP Requests

Make multiple HTTP requests simultaneously:

```javascript
(payload) => {
  const { input } = payload;
  
  return {
    "lam.httpRequests": [
      {
        "method": "GET",
        "url": "{{props.baseUrl}}/inventory/{{input.itemId}}",
        "pathParams": {
          "itemId": input.itemId
        }
      },
      {
        "method": "GET",
        "url": "{{props.baseUrl}}/pricing/{{input.itemId}}",
        "pathParams": {
          "itemId": input.itemId
        }
      }
    ]
  };
}
```

#### Conditional Workflow Exit

Exit workflows early based on conditions:

```javascript
(payload) => {
  const { step_1 } = payload;
  
  if (step_1.inventory.quantity < 1) {
    return {
      "lam.exit": true,
      "data": {
        "error": "Out of stock"
      }
    };
  }
  
  // Continue processing...
}
```

#### Async Workflow Execution

Trigger other workflows asynchronously:

```javascript
(payload) => {
  return {
    "lam.asyncExecute": [
      {
        "lam.workflowId": 789,
        "lam.payload": {
          "orderId": payload.input.orderId,
          "event": "ORDER_CREATED"
        }
      }
    ],
    "data": {
      "status": "processing"
    }
  };
}
```

### Best Practices

#### Configuration Management

* Store environment-specific values in configuration store
* Use `{{props.propertyName}}` syntax for references
* Keep sensitive data in configuration store

#### Error Handling

* Use try-catch blocks in transformations
* Return meaningful error messages
* Use `lam.exit` for critical errors

#### Data Flow

* Access previous step data using `step_X` notation
* Keep transformations focused and single-purpose
* Use meaningful names for flows and properties

#### Security

* Use separate configuration stores per environment
* Rotate credentials regularly
* Implement role-based access control for configuration stores


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.laminar.run/building-an-integration/advanced/workflows/how-to-build.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
