Actions
Learn about the different action types in ThinkFleet: piece actions, code actions, branching, and loops.
Actions
Actions are the steps in your flow that perform work after the trigger fires. ThinkFleet provides several action types to handle different scenarios.
Piece Actions
Piece actions are operations provided by integration pieces. They interact with external services through their APIs.
Adding a Piece Action
- Click + below any step
- Search for a piece by name or browse by category
- Select the specific action
- Connect your account (or select an existing connection)
- Configure the action inputs
Example: Create a Google Sheets Row
Piece: Google Sheets
Action: Insert Row
Connection: my-google-account
Settings:
Spreadsheet: "Sales Tracker"
Sheet: "Sheet1"
Values:
Column A: "{{trigger.body.customerName}}"
Column B: "{{trigger.body.email}}"
Column C: "{{trigger.body.orderTotal}}"
Dynamic Inputs
Most piece action inputs support dynamic values using the data reference syntax:
Static value: Hello World
Dynamic value: {{trigger.body.name}}
Mixed: Order #{{step_1.orderId}} confirmed
Code Actions
Code actions let you run custom JavaScript/TypeScript when pieces don't cover your use case.
Writing Code Actions
export const code = async (inputs) => {
// inputs contains data you configure in the step settings
const orders = inputs.orders;
// Perform any computation
const summary = {
total: orders.reduce((sum, o) => sum + o.amount, 0),
count: orders.length,
average: orders.reduce((sum, o) => sum + o.amount, 0) / orders.length,
highestOrder: Math.max(...orders.map(o => o.amount)),
};
// Return data for subsequent steps
return summary;
};
Code Action Inputs
Define inputs in the step configuration panel to pass data from previous steps into your code:
| Input Name | Value |
|---|---|
orders |
{{step_1.response.data}} |
threshold |
500 |
These become available as inputs.orders and inputs.threshold in your code.
Using npm Packages
You can import npm packages in code actions. Declare them in the Packages section of the step settings:
{
"axios": "1.6.0",
"lodash": "4.17.21",
"date-fns": "3.0.0"
}
Then use them in your code:
import axios from 'axios';
import { groupBy } from 'lodash';
import { format } from 'date-fns';
export const code = async (inputs) => {
const response = await axios.get('https://api.example.com/data', {
headers: { Authorization: `Bearer ${inputs.apiKey}` },
});
const grouped = groupBy(response.data, 'category');
return {
data: grouped,
fetchedAt: format(new Date(), 'yyyy-MM-dd HH:mm:ss'),
};
};
Code Action Limitations
- Timeout: Code actions have a maximum execution time (default: 30 seconds, configurable)
- Memory: Limited to 256 MB by default
- Network: Outbound HTTP is allowed; inbound connections are not
- File system: Read-only access to a temporary directory
Branch (Conditional Logic)
Branch actions split your flow into two paths based on a condition.
Setting Up a Branch
- Click + and select Branch
- Configure the condition:
| Component | Example |
|---|---|
| Field 1 | {{trigger.body.status}} |
| Operator | Equals |
| Field 2 | "approved" |
- Add steps to the True branch (executes when condition is met)
- Add steps to the False branch (executes when condition is not met)
Available Operators
| Operator | Description |
|---|---|
| Equals | Exact string/number match |
| Not Equals | Does not match |
| Contains | String contains substring |
| Does Not Contain | String does not contain substring |
| Greater Than | Numeric comparison |
| Less Than | Numeric comparison |
| Is Empty | Field is null, undefined, or empty string |
| Is Not Empty | Field has a value |
| Starts With | String starts with prefix |
| Ends With | String ends with suffix |
Multiple Conditions
Combine conditions with AND / OR logic:
IF (status equals "approved") AND (amount > 1000)
→ Route to finance team
ELSE
→ Route to standard processing
Nested Branches
You can nest branches inside other branches for complex decision trees:
IF region equals "US"
IF tier equals "enterprise"
→ Assign to US Enterprise team
ELSE
→ Assign to US General team
ELSE
→ Assign to International team
Loops
Loop actions iterate over an array and execute child actions for each element.
Setting Up a Loop
- Click + and select Loop
- Set Items to an array:
{{step_1.response.items}} - Add child actions inside the loop body
Accessing Loop Data
Inside a loop, use these references:
| Reference | Description |
|---|---|
{{loop.item}} |
The current item in the iteration |
{{loop.index}} |
The current index (0-based) |
Example: Send Personalized Emails
Trigger: Schedule (daily at 9 AM)
Step 1: Query database for today's birthdays
Loop over: {{step_1.customers}}
→ Send Email:
To: {{loop.item.email}}
Subject: "Happy Birthday, {{loop.item.firstName}}!"
Body: "Here's a special 20% discount code: BDAY-{{loop.item.customerId}}"
Loop Performance
- Loops execute iterations sequentially
- Each iteration counts as a separate task execution for billing purposes
- For very large arrays (1000+ items), consider using batch APIs instead of looping
HTTP Request Action
The built-in HTTP Request action lets you call any REST API directly without needing a dedicated piece.
Configuration
Method: POST
URL: https://api.example.com/v1/records
Headers:
Authorization: "Bearer {{connections['my-api-key']}}"
Content-Type: "application/json"
Body:
{
"name": "{{trigger.body.name}}",
"email": "{{trigger.body.email}}"
}
Response Handling
The HTTP Request action returns:
{
"status": 201,
"headers": { "content-type": "application/json" },
"body": { "id": "rec_123", "created": true }
}
Access the response in subsequent steps:
{{http_request_1.body.id}} → "rec_123"
{{http_request_1.status}} → 201
Action Execution Order
Actions execute sequentially from top to bottom. Each action waits for the previous action to complete before starting. Within a branch, only the matching path executes. Within a loop, the child actions execute sequentially for each iteration.