# Flow Integration

Integrate Onboarded™ sync operations into your Salesforce Flows using invocable actions. The application provides two invocable actions for different use cases.

## Onboarded™ Data Sync Invocable

Action Label: `Onboarded™ Data Sync`

Syncs existing Salesforce records to Onboarded™ using your configured field mappings. This action reads data from Salesforce records and maps it to Onboarded™ API fields based on your mapping configuration.

| Parameter | Required | Description |
|  --- | --- | --- |
| `Salesforce Object` | Required | The Salesforce object of the record to be synced (e.g., Contact, Lead, Account, Person Account) |
| `Record IDs` | Required | The Salesforce Record IDs to sync |
| `Sync Operation` | Optional | Create, Update, or Delete (defaults to Update if not provided) |
| `Onboarded™ Object` | Optional | Specify the Onboarded™ object type (Employee, Employer, Client, etc.). Required when Account is used for both Person Account (Employee) and Business Account (Employer). |


**When to Use:** Ideal for scenarios where a Salesforce record is created or updated and needs to be synced to Onboarded™. The application automatically handles field mapping based on your configuration, making this the simplest approach for standard sync operations.

> **Common Scenarios:**
- **Record Created in Salesforce:** Use `operation='Create'` to create a corresponding Employee/Employer/Client in Onboarded™
- **Record Updated in Salesforce:** Use `operation='Update'` (default) to sync changes to existing Onboarded™ record
- **Record Deleted in Salesforce:** Use `operation='Delete'` to remove from Onboarded™



> **Critical Requirement for Create Operations:** When using Flows or Apex code to **create** records in your Onboarded account from Salesforce, you MUST configure the **"id" field** mapping with **Sync Operation = "Bidirectional"** for the target Onboarded object type (Employee, Employer, Client, etc.).
**Why this matters:** After Onboarded creates the new record, it generates a unique Onboarded ID (e.g., `ee_abc123`). The queueable job needs to write this ID back to your Salesforce record's Onboarded ID field. If the mapping is set to "Outbound" only, the queueable operation cannot update the Salesforce record with the newly created Onboarded ID, and future sync operations will fail because Salesforce won't know which Onboarded record corresponds to the Salesforce record.
**How to configure:**
- Navigate to **Onboarded Setup** → **Field Mappings** tab
- Locate the object section (e.g., Employee, Employer, Client)
- Find the **"id"** field mapping row
- Set **Sync Operation** to **"Bidirectional"**
- Save your changes



### Record-Triggered Flow Example — Contact Creation

1. **Create Record-Triggered Flow.** Create a flow triggered when a Contact is created or updated.
  - Object: Contact
  - Trigger: When a record is created or updated
  - Entry Conditions: [Optional — add criteria if needed]
  - Optimize Flow: Fast Field Updates
2. **Add Action Element.** Add an Action element and search for "Onboarded™ Data Sync".
3. **Configure Parameters.**
  - **Salesforce Object:** `Contact`
  - **Record IDs:** `{!$Record.Id}`
  - **Sync Operation:** `Create` (for new records) or `Update` (for existing records)
  - **Onboarded™ Object:** `Employee`


> **Why Use This Approach:** This invocable automatically reads the Contact record's fields and applies your configured field mappings. You don't need to specify which fields to sync — the application handles that based on your Field Mapping configuration in Onboarded™ Setup.


## Invoke Onboarded™ API Invocable

Action Label: `Invoke Onboarded™ API`

Sends data directly to the Onboarded™ API using custom key-value pairs that you define. This action gives you full control over the API payload without relying on field mappings.

| Parameter | Required | Description |
|  --- | --- | --- |
| `Onboarded™ Object` | Required | The Onboarded™ object type (e.g., Employee, Employer, Client, Job, Placement, Task). Must match the Onboarded™ API object name. |
| `API Action` | Required | The API operation to perform: Create, Update, or Delete |
| `Key/Value Pairs Collection` | Required | A collection of the `ApiKeyValuePair` Apex-defined type representing the API payload. Keys must match Onboarded™ API field names exactly. See **ApiKeyValuePair Class** below for setup details. |


> **Important:** When using this action, you are responsible for:
- Providing correct Onboarded™ API field names as keys
- Providing values in the correct data type expected by the API
- Including all required fields for the target Onboarded™ object



**When to Use:** Ideal for scenarios where you need to aggregate data from multiple Salesforce objects or sources before creating an Onboarded™ record. Unlike Onboarded Data Sync (which operates on a single Salesforce record), this invocable lets you construct a custom payload from any data combination.

### Synchronous vs Asynchronous Execution

This action intelligently determines the best execution path based on your Flow context:

| Context | Execution | Response |
|  --- | --- | --- |
| Screen Flow / Quick Action (single record) | Synchronous | Actual API response (JSON with Onboarded ID) or error message |
| Screen Flow / Quick Action (multiple records) | Error | "Synchronous sync supports single record only" |
| Record-Triggered Flow | Asynchronous | "Queueable enqueued for API call..." |
| Inbound sync in progress | Deferred | "Queued for deferred processing..." |


> **Synchronous Execution Benefits:** When using Screen Flows or Quick Actions with a single record, you receive the actual API response immediately. This allows you to:
- Capture the new Onboarded ID from Create operations
- Display success/error messages to users immediately
- Use Decision elements to handle API errors within your Flow
- Provide real-time feedback in user-facing interactions



> **Common Scenarios:**
- **Multi-Object Data Assembly:** Create an Employee in Onboarded™ using data from Contact, Account, and custom objects combined
- **Custom Data Transformations:** Apply business logic or calculations before sending to Onboarded™
- **Non-Standard Mappings:** Send data that doesn't follow your configured field mappings (one-off scenarios)
- **Screen Flow User Input:** Create Onboarded™ records directly from user-entered data in Screen Flows



> **Critical Requirement for Create Operations:** When using this action with **API Action = "Create"**, you MUST configure the **"id" field** mapping with **Sync Operation = "Bidirectional"** for the target Onboarded object type.
**Why this matters:** After Onboarded creates the new record and generates its unique ID (e.g., `ee_abc123`), the queueable job needs to write this ID back to your Salesforce record. Without Bidirectional sync for the "id" field, the Salesforce record won't receive the Onboarded ID, causing future sync operations to fail.
**Configuration:** Navigate to **Onboarded Setup** → **Field Mappings** → locate the object section → set the **"id"** field's Sync Operation to **"Bidirectional"**.


### ApiKeyValuePair Class

The application provides the `ApiKeyValuePair` Apex class to facilitate building key-value pair collections in Flow. This class has two properties that are exposed to Flow:

- `key` — The Onboarded™ API field name (must match exactly)
- `value` — The value to send for that field


### Multi-Source Employee Creation Example

This example demonstrates how to create an Employee in Onboarded™ by combining data from a Contact record, related Account, and a custom object using Loop and Assignment elements.

1. **Create Your Flow.** Create a Record-Triggered Flow, Screen Flow, or Autolaunched Flow based on your use case.
  - Example: Record-Triggered Flow when Contact is created
  - Or: Screen Flow where user selects multiple data sources
2. **Create Flow Variables.** Create the following variables in your Flow:
| Variable Name | Data Type | Purpose |
|  --- | --- | --- |
| `varKeyValuePair` | ApiKeyValuePair (Apex-Defined) | Temporary holder for individual key-value pairs |
| `colKeyValuePairs` | ApiKeyValuePair (Collection) | Collection of all key-value pairs to send to API |
| `colFieldsToMap` | Text (Collection) | List of Onboarded™ field names to populate (optional, for loop-based approach) |
3. **Query Related Records (if needed).** If your data comes from multiple objects, use Get Records elements to retrieve related data:
  - Get Account record related to Contact
  - Get custom object records via lookup relationships
  - Store results in record variables for later use
4. **Build Key/Value Pairs Using Loop and Assignment.** Use a Loop element to iterate through field mappings, with an Assignment element inside the loop to build each key-value pair. This approach is cleaner and more maintainable than creating multiple Assignment elements.
#### Loop Through Field List (Recommended for Many Fields)
  1. **Create Assignment Element:** Populate `colFieldsToMap` with field names you need to send:
    - Add: `first_name`
    - Add: `last_name`
    - Add: `email`
    - Add: `phone`
    - Add: `employer_id`
  2. **Add Loop Element:** Loop through `colFieldsToMap`, storing current item in `varCurrentField`
  3. **Inside Loop — Add Assignment Element:** For each field:
    - Set `varKeyValuePair.key` = `{!varCurrentField}`
    - Set `varKeyValuePair.value` = `[Use Decision element or formula to map field name to actual value]`
    - Add `varKeyValuePair` to `colKeyValuePairs` collection
    - **IMPORTANT:** Clear the temporary variable by setting `varKeyValuePair.key` = `null` and `varKeyValuePair.value` = `null`
> **Critical Step:** After adding `varKeyValuePair` to the collection, you MUST clear the `key` and `value` properties by setting them to null. This prevents the previous iteration's values from carrying over to the next iteration.
#### Individual Assignment Elements (Simple, for Few Fields)
For flows with only a few fields (5 or less), you can create separate Assignment elements:
  1. **Assignment 1 — First Name:**
    - Set `varKeyValuePair.key` = `first_name`
    - Set `varKeyValuePair.value` = `{!$Record.FirstName}`
    - Add `varKeyValuePair` to `colKeyValuePairs`
    - Set `varKeyValuePair.key` = `null`
    - Set `varKeyValuePair.value` = `null`
  2. **Assignment 2 — Last Name:**
    - Set `varKeyValuePair.key` = `last_name`
    - Set `varKeyValuePair.value` = `{!$Record.LastName}`
    - Add `varKeyValuePair` to `colKeyValuePairs`
    - Set `varKeyValuePair.key` = `null`
    - Set `varKeyValuePair.value` = `null`
  3. **Repeat for remaining fields...**
5. **Add the Invoke Onboarded™ API Action.** Add an Action element and search for "Invoke Onboarded™ API".
6. **Configure the Action Parameters.**
  - **Onboarded™ Object:** `Employee`
  - **API Action:** `Create`
  - **Key/Value Pairs Collection:** `{!colKeyValuePairs}`


### Employee Field Reference

When creating an Employee in Onboarded™, you would build key-value pairs like these:

| Key (API Field Name) | Value Source (Example) | Notes |
|  --- | --- | --- |
| `first_name` | `{!$Record.FirstName}` | From Contact record |
| `last_name` | `{!$Record.LastName}` | From Contact record |
| `email` | `{!$Record.Email}` | From Contact record |
| `phone` | `{!$Record.Phone}` | From Contact record |
| `employer_id` | `{!varAccountOnboardedId}` | From related `Account.Onboarded_Id__c` (queried via Get Records) |
| `start_date` | `{!varCustomObject.Start_Date__c}` | From custom object (queried via Get Records) |


**API Reference:** Consult the Onboarded™ API documentation at `https://app.onboarded.com/api/v1/openapi.json` for the complete list of available fields and required fields for each object type.

> **Why Use This Approach:** Unlike Onboarded Data Sync (which pulls data from a single Salesforce record), this invocable allows you to combine data from Contact, Account, custom objects, and even user-entered Screen Flow data into a single Onboarded™ API call. This is ideal when no single Salesforce record contains all the data needed.


## Invocable Best Practices

### Re-entrancy Protection

Both invocable actions include built-in protection against infinite loops. If an outbound sync is already in progress, subsequent calls will be skipped to prevent recursive execution.

**What This Means:** If your Flow triggers on record update and the invocable updates the same record (via sync queue processing), the trigger won't fire again, preventing an infinite loop.

### Queueable Limits and Deferred Processing

Both invocables use queueable jobs to make API callouts. When Salesforce queueable limits are reached, requests are automatically queued in `Onboarded_Sync_Queue__c` for later processing.

**What This Means:** Your Flow will always complete successfully, even if the API call can't be made immediately. Failed or deferred requests can be monitored via the Sync Queue object.

### Invocable Selection Guide

| Scenario | Use This Invocable | Why |
|  --- | --- | --- |
| Single Salesforce record created/updated | **Onboarded™ Data Sync** | Automatically applies configured field mappings |
| Data from multiple Salesforce objects | **Invoke Onboarded™ API** | Allows assembly from multiple sources |
| User-entered data in Screen Flow | **Invoke Onboarded™ API** | Can send any data, not tied to records |
| Custom calculations/transformations needed | **Invoke Onboarded™ API** | Full control over payload construction |
| Standard sync with mapped fields | **Onboarded™ Data Sync** | Simpler configuration, no key-value pairs needed |


> **Pro Tip:** When building complex Flows with many fields using Invoke Onboarded™ API, consider creating a reusable subflow that handles the key-value pair construction. Pass the source record into the subflow, and return the constructed collection. This makes your main Flow cleaner and the logic reusable across multiple flows.