> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connector Structure

> Learn how Falcon connectors are structured — file organization, authentication, actions, step functions, and expressions

This guide walks through the structure of StackOne's Falcon connectors — how files are organized, how authentication works, how actions and steps fit together, and how expressions let you wire data between them. For detailed property-by-property documentation, see the [YAML Reference](/guides/connector-engine/connector-yaml-reference). For working examples, see the [connectors-template repository](https://github.com/StackOneHQ/connectors-template).

***

## File Structure

Connectors are organized into a main connector file and (optionally) partial files for each resource:

```
connectors/{provider}/
├── {provider}.connector.s1.yaml           # Main connector (auth, metadata)
└── {provider}.{resource}.s1.partial.yaml  # Actions for each resource
```

**Naming conventions:**

* Use kebab-case for file names
* Reference partials in the main file using `$ref: provider.resource`
* Add references in alphabetical order (not required, but recommended for readability)

***

## Main Connector File

The main connector file defines metadata, authentication, and references to action partials.

```yaml theme={null}
StackOne: 1.0.0
info:
  title: Provider Name
  key: provider
  version: 1.0.0
  assets:
    icon: https://stackone-logos.com/api/provider/filled/png
  description: Brief description of the provider

baseUrl: https://api.provider.com/v1

rateLimit:
  mainRatelimit: 10  # Requests per second

context: "Provider API documentation: https://api.provider.com/docs"

authentication:
  - custom:
      # ... authentication config

actions:
  - $ref: provider.users
  - $ref: provider.files
```

### Info Section

| Field         | Required | Description                                                                        |
| ------------- | -------- | ---------------------------------------------------------------------------------- |
| `title`       | Yes      | Display name shown in the StackOne Hub and dashboard                               |
| `key`         | Yes      | Unique lowercase identifier used in action names (e.g., `bamboohr_list_employees`) |
| `version`     | Yes      | Semantic version for tracking connector changes                                    |
| `assets.icon` | No       | URL to provider logo (displayed in Hub and dashboard)                              |
| `description` | No       | Brief description for documentation and AI context                                 |

<Accordion title="When to use each field">
  * **`title`**: User-facing name. Use the official provider name (e.g., "BambooHR" not "Bamboo HR")
  * **`key`**: Machine-readable identifier. Must be lowercase with underscores. Cannot be changed after deployment without breaking existing integrations
  * **`version`**: Increment when making changes. Use semantic versioning: major.minor.patch
  * **`assets.icon`**: Use `https://stackone-logos.com/api/{key}/filled/png` for consistent styling
  * **`description`**: Keep concise. Used by AI agents for context when discovering connectors
</Accordion>

### Base URL

The `baseUrl` defines the root URL for all API requests. It supports credential interpolation for providers with dynamic domains.

```yaml theme={null}
# Static base URL
baseUrl: https://api.provider.com/v1

# Dynamic subdomain from credentials
baseUrl: https://${credentials.subdomain}.api.provider.com/v2

# Region-specific endpoint
baseUrl: https://api.${credentials.region}.provider.com/v1
```

<Accordion title="When to use dynamic baseUrl">
  Use credential interpolation when the provider requires:

  * **Customer-specific subdomains**: Many B2B SaaS products use `{company}.provider.com` URLs
  * **Region selection**: Some providers have separate endpoints per region (US, EU, APAC)
  * **Environment switching**: Sandbox vs production endpoints

  The interpolated values come from `configFields` in your authentication config. These are fields your customer fills in when connecting their account.
</Accordion>

***

## Authentication

Authentication is defined once in the main connector file. All actions inherit it.

### Setup vs Config Fields

| Field Type     | Who Fills It        | When                         | Example                          |
| -------------- | ------------------- | ---------------------------- | -------------------------------- |
| `setupFields`  | You (the developer) | Dashboard integration config | Client ID, Client Secret, Scopes |
| `configFields` | Your customer       | Hub account connection       | API Token, Subdomain             |

<Accordion title="Choosing between setupFields and configFields">
  **Use `setupFields` for:**

  * OAuth client credentials (Client ID, Client Secret)
  * Scopes that you control
  * API keys that belong to your app, not the end user
  * Values you configure once in the StackOne dashboard

  **Use `configFields` for:**

  * Customer's own API tokens or keys
  * Customer-specific identifiers (subdomain, account ID, workspace ID)
  * Any value that differs per customer connection
  * Values the customer enters in the Hub when linking their account

  **Field properties:**

  * `secret: true`: Masks the field value and encrypts storage (use for tokens, keys, passwords)
  * `required: true`: Field must be filled before connection can complete
  * `placeholder`: Shows example format without exposing real values
  * `tooltip`: Additional help text shown on hover
</Accordion>

### Example: API Key Authentication

```yaml theme={null}
authentication:
  - custom:
      type: custom
      label: API Key
      support:
        link: https://your-connection-guide-url-here.com
        description: Steps require Admin privileges
      authorization:
        type: bearer
        token: $.credentials.apiKey
      configFields:
        - key: apiKey
          label: API Key
          type: password
          required: true
          secret: true
          placeholder: sk_live_xxxxx
          description: Generate in Settings > API Keys
      environments:
        - key: production
          name: Production
      testActionsIds:
        - list_users
```

### Other Authentication Types

The Falcon engine supports several authorization types:

| Type               | `authorization.type`     | Use Case                                                            |
| ------------------ | ------------------------ | ------------------------------------------------------------------- |
| **Bearer token**   | `bearer`                 | API key or OAuth access token in `Authorization: Bearer` header     |
| **Basic auth**     | `basic`                  | Username/password encoded as `Authorization: Basic` header          |
| **Custom headers** | `none` + `customHeaders` | Provider-specific header-based auth                                 |
| **OAuth 2.0**      | `oauth2`                 | Full OAuth flow with authorization URL, token exchange, and refresh |

<Tip>
  For complete authentication examples including OAuth 2.0 with token refresh, see the [YAML Reference — Authentication](/guides/connector-engine/connector-yaml-reference#authentication).
</Tip>

***

## Actions

Actions define the operations your connector can perform. Each action consists of metadata, inputs, steps, and result configuration.

### Action Structure

```yaml theme={null}
- actionId: list_users
  categories:
    - hris
  actionType: list
  schema: users
  label: List Users
  description: Get all users with pagination
  context: https://api.provider.com/docs/users/list
  entrypointUrl: /users
  entrypointHttpMethod: get
  inputs:
    - name: page_size
      type: number
      in: query
      required: false
      description: Results per page (max 100)
  steps:
    - stepId: fetch_users
      stepFunction:
        functionName: request
        parameters:
          url: /users
          method: get
  result:
    data: $.steps.fetch_users.output.data
```

| Field                  | Required    | Description                                                                                                                                                |
| ---------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `actionId`             | Yes         | Unique identifier within the connector. Forms the action name: `{connector_key}_{actionId}`                                                                |
| `categories`           | Yes         | Array of verticals this action belongs to (e.g., `hris`, `ats`, `crm`). See [YAML Reference](/guides/connector-engine/connector-yaml-reference#categories) |
| `actionType`           | Yes         | Identifies the type of the action (`list`, `get`, `create`, `update`, `delete`, `custom`)                                                                  |
| `schema`               | Conditional | Required for unified actions. Specifies which StackOne schema to map to                                                                                    |
| `label`                | Yes         | Human-readable name shown in Actions Explorer and AI tool descriptions                                                                                     |
| `description`          | Yes         | Explains what the action does. Used by AI agents for tool selection                                                                                        |
| `context`              | No          | URL to provider API docs. Helps AI agents understand the action                                                                                            |
| `entrypointUrl`        | No          | Alternative to defining URL in steps. The main endpoint path                                                                                               |
| `entrypointHttpMethod` | No          | Alternative to defining method in steps. HTTP method to use                                                                                                |

<Accordion title="How these fields affect your action">
  * **`actionId`**: Keep it descriptive and follow the pattern `{verb}_{resource}` (e.g., `list_users`, `get_employee`, `create_candidate`). Cannot be changed after deployment.
  * **`categories`**: Determines where the action appears in the Actions Explorer. An action can belong to multiple categories.
  * **`actionType`**: Choosing `custom` is fastest since no schema mapping is needed. Use unified types (`list`, `get`, etc.) when you want cross-provider compatibility.
  * **`schema`**: Must match a StackOne schema name (e.g., `users`, `employees`, `candidates`). Only required when `actionType` is unified.
  * **`label` + `description`**: These appear in the Actions Explorer and are sent to AI agents. Write them for humans, not machines.
  * **`context`**: Adding the provider's API doc URL helps the Builder Agent and AI tools understand edge cases.
</Accordion>

### Action Types

| Type            | Description                                                         |
| --------------- | ------------------------------------------------------------------- |
| `list`          | Retrieve multiple records, typically with pagination                |
| `get`           | Retrieve a single record by identifier                              |
| `create`        | Create a new resource                                               |
| `update`        | Modify an existing resource                                         |
| `delete`        | Remove a resource                                                   |
| `custom`        | Provider-specific operation that doesn't fit standard CRUD patterns |
| `refresh_token` | Internal OAuth token refresh (use with `internal` category)         |

Add a `schema` field to map provider data to StackOne's standardized schemas (e.g., `schema: employees`). Without `schema`, the action returns provider data as-is. See [Field Configs](#field-configs-unified-actions) for mapping details.

### Inputs

Inputs define the parameters your action accepts. Each input specifies a `name`, `type`, location (`in`), and whether it's `required`:

```yaml theme={null}
inputs:
  - name: id
    type: string
    in: path           # URL path parameter (/users/${inputs.id})
    required: true
  - name: status
    type: string
    in: query          # Query string (?status=active)
    required: false
  - name: email
    type: string
    in: body           # Request body field
    required: true
```

**Input types:** `string`, `number`, `boolean`, `datetime_string`, `object`
**Input locations:** `path`, `query`, `body`, `headers`

For full input property documentation including nested objects, see the [YAML Reference — Inputs](/guides/connector-engine/connector-yaml-reference#inputs).

***

## Step Functions

Step functions are the building blocks of actions. Each step performs one operation.

<Accordion title="Choosing the right step function">
  | Scenario                                      | Use                                                     |
  | --------------------------------------------- | ------------------------------------------------------- |
  | Single API call (get user, create record)     | `request`                                               |
  | List endpoint with cursor pagination          | `paginated_request`                                     |
  | List endpoint with offset/page pagination     | `request` + manual cursor handling                      |
  | Per-item API calls (detail fetch for each ID) | `request` with [iterator step](#iterator-steps-foreach) |
  | Transform provider data to output schema      | `map_fields`                                            |
  | Convert field types after mapping             | `typecast`                                              |
  | Merge results from multiple API calls         | `group_data`                                            |
  | Return hardcoded enum values                  | `static_values`                                         |
  | Combine static + dynamic data                 | `merge_collections`                                     |
  | Upload a file                                 | `upload_file`                                           |
  | Download a file                               | `download_file`                                         |
  | SOAP/XML API call                             | `soap_request`                                          |
  | Invoke an AWS Lambda function                 | `code_execution_lambda`                                 |

  **Common patterns:**

  * **GET single resource**: `request` → `result`
  * **LIST with pagination**: `paginated_request` → `result`
  * **Unified action**: `request` → `map_fields` → `typecast` → `result`
  * **Multi-source data**: `request` (x2) → `group_data` → `result`
  * **Per-item enrichment**: `request` → iterator `request` → `group_data` → `result`
  * **Static + dynamic merge**: `static_values` + `request` → `merge_collections` → `result`
</Accordion>

### `request` - HTTP Requests

Make a single HTTP request to the provider API. Use `args` to pass headers, query parameters, and body fields. Use `response.dataKey` to extract nested data from the response.

```yaml theme={null}
steps:
  - stepId: get_user
    description: Fetch user by ID
    stepFunction:
      functionName: request
      parameters:
        url: /users/${inputs.id}
        method: get
        args:
          - name: include_details
            value: "{{inputs.include_details}}"
            in: query
            condition: "{{present(inputs.include_details)}}"
        response:
          collection: false
          dataKey: user
```

<Warning>
  Always use `args` for request parameters. Never use a direct `body` field.
</Warning>

### `paginated_request` - Cursor Pagination

Automatically fetches all pages using cursor-based pagination. StackOne handles cursor tracking, page assembly, and continuation logic.

```yaml theme={null}
steps:
  - stepId: list_users
    stepFunction:
      functionName: paginated_request
      parameters:
        url: /users
        method: get
        response:
          dataKey: results       # Where to find the data array
          nextKey: nextCursor    # Where to find the next cursor
        iterator:
          key: cursor            # Parameter name to pass cursor
          in: query              # Where to send it (query or body)
        args:
          - name: limit
            value: "100"
            in: query
```

**How it works:** Makes the initial request, extracts results from `response.dataKey`, checks `response.nextKey` for a continuation cursor, and repeats until no cursor is returned. All pages are combined automatically.

<Warning>
  **Only use `paginated_request` for cursor-based pagination.** For offset or page-based pagination, use a regular `request` step with manual cursor handling.
</Warning>

### `map_fields` - Transform Data

Transform provider response data into your output schema. Takes a `dataSource` (typically a previous step's output), evaluates an `expression` per field against each record, and converts to the specified `type`.

```yaml theme={null}
steps:
  - stepId: map_data
    description: Map user data
    stepFunction:
      functionName: map_fields
      version: "2"
      parameters:
        dataSource: $.steps.fetch_users.output.data
        fields:
          - targetFieldKey: id
            expression: $.user_id
            type: string
          - targetFieldKey: full_name
            expression: "{{$.first_name + ' ' + $.last_name}}"
            type: string
          - targetFieldKey: is_active
            expression: $.status == 'active'
            type: boolean
```

Supports enum mapping, nested objects, and JEXL expressions for complex transformations. See [YAML Reference — map\_fields](/guides/connector-engine/connector-yaml-reference#map_fields) for the full list of field config options.

### `typecast` - Type Conversion

Apply type conversions to data. Used for unified actions.

```yaml theme={null}
steps:
  - stepId: typecast_data
    description: Apply types
    stepFunction:
      functionName: typecast
      version: "2"
      parameters:
        dataSource: $.steps.map_data.output.data
        fields:
          - targetFieldKey: created_at
            type: datetime_string
          - targetFieldKey: salary
            type: number
          - targetFieldKey: is_manager
            type: boolean
```

### `group_data` - Combine Results

Merge data from multiple steps into a single dataset.

```yaml theme={null}
steps:
  - stepId: combine_data
    stepFunction:
      functionName: group_data
      parameters:
        stepsDataToGroup:
          - fetch_employees
          - fetch_contractors
        isSingleRecord: false
```

### `static_values` - Return Static Data

Return predefined values without making an API request. Useful for enum lookups or constant data.

```yaml theme={null}
steps:
  - stepId: ticket_types
    stepFunction:
      functionName: static_values
      parameters:
        values:
          - id: question
            name: Question
          - id: incident
            name: Incident
```

### `merge_collections` - Merge Arrays

Merge multiple data collections into a single array.

```yaml theme={null}
steps:
  - stepId: all_types
    stepFunction:
      functionName: merge_collections
      parameters:
        collections:
          - $.steps.static_types.output.data
          - $.steps.api_types.output.data
```

### `upload_file` / `download_file` - File Operations

Handle file uploads (multipart form) and downloads (with encoding options).

```yaml theme={null}
# Upload
- stepId: upload_document
  stepFunction:
    functionName: upload_file
    parameters:
      url: /files/upload
      method: post
      file:
        fieldName: file
        content: $.inputs.file_content
        filename: $.inputs.filename

# Download
- stepId: download_document
  stepFunction:
    functionName: download_file
    parameters:
      url: /files/${inputs.file_id}/content
      method: get
      encoding: base64
```

### `soap_request` - SOAP API

Make SOAP (XML) requests. Used for enterprise providers like Workday.

```yaml theme={null}
steps:
  - stepId: get_workers
    stepFunction:
      functionName: soap_request
      parameters:
        url: /Human_Resources
        method: post
        soapOperation: Get_Workers
        soapAction: http://example.com/Get_Workers
        namespaces:
          - namespaceIdentifier: bsvc
            namespace: urn:com.workday/bsvc
```

### `code_execution_lambda` - AWS Lambda Invocation

Invoke an AWS Lambda function and use its response as the step output. Use for custom transformations or provider-specific logic that doesn't fit other step functions. The `args` array is assembled into the JSON payload sent to the Lambda.

```yaml theme={null}
steps:
  - stepId: enrich_user
    stepFunction:
      functionName: code_execution_lambda
      parameters:
        lambdaName: my-lambda-function
        region: us-east-1
        invocationType: RequestResponse
        args:
          - name: userId
            value: $.inputs.user_id
          - name: count
            value: $.inputs.count
```

See [YAML Reference — code\_execution\_lambda](/guides/connector-engine/connector-yaml-reference#code_execution_lambda) for all parameters, invocation types, and output fields.

<Tip>
  For full parameter documentation on all step functions, see the [YAML Reference — Steps](/guides/connector-engine/connector-yaml-reference#steps).
</Tip>

***

## Iterator Steps (Foreach)

Iterator steps execute one or more step functions for each item in a collection. Use them when you need to make per-item API calls — for example, fetching detailed data for each record returned by a list endpoint.

### Structure

An iterator step is defined by adding the `iterator` property to a step. The `iterator` value is a JSONPath expression that resolves to an array.

```yaml theme={null}
steps:
  - stepId: get_employee_details
    description: Fetch detailed data for each employee
    iterator: $.steps.list_employees.output.data.employees[*].id
    stepFunction:
      functionName: request
      parameters:
        url: /employees/${iterator.item}
        method: get
        response:
          collection: false
```

### How It Works

1. The `iterator` expression is evaluated to produce an array
2. For each item in the array, the step function(s) execute
3. Inside the step, you can access:
   * `$.iterator.item` — the current array element
   * `$.iterator.index` — the current iteration index (0-based)
   * `$.iterator.current` — the output of the previous step function in the same iteration (when using `stepFunctions`)
4. All iteration outputs are collected into an array at `$.steps.{stepId}.output.data`

### Single Step Function

The most common pattern — make one API call per item:

```yaml theme={null}
steps:
  - stepId: list_employees
    description: Get all employee IDs
    stepFunction:
      functionName: request
      parameters:
        url: /employees
        method: get
        response:
          collection: true
          dataKey: employees

  - stepId: get_employee_details
    description: Fetch details for each employee
    iterator: $.steps.list_employees.output.data.employees[*].id
    stepFunction:
      functionName: request
      parameters:
        url: /employees/${iterator.item}
        method: get
        response:
          collection: false
```

### Multiple Step Functions

Use `stepFunctions` (plural) to execute a sequence of functions per iteration. Each function can access the output of the previous one via `$.iterator.current`:

```yaml theme={null}
steps:
  - stepId: enrich_employees
    description: Fetch and transform data for each employee
    iterator: $.steps.list_employees.output.data.employees[*].id
    stepFunctions:
      - functionName: request
        parameters:
          url: /employees/${iterator.item}/details
          method: get
          response:
            collection: false
      - functionName: request
        parameters:
          url: /employees/${iterator.item}/compensation
          method: get
          response:
            collection: false
```

<Warning>
  You must provide either `stepFunction` (singular) or `stepFunctions` (plural) — not both. The YAML validator enforces this.
</Warning>

### Conditional Iterator

Like regular steps, iterator steps support the `condition` and `ignoreError` properties:

```yaml theme={null}
steps:
  - stepId: get_employee_managers
    description: Fetch manager data if employees have managers
    iterator: $.steps.list_employees.output.data.employees[*]
    condition: '{{present(steps.list_employees.output.data.employees)}}'
    ignoreError: true
    stepFunction:
      functionName: request
      parameters:
        url: /employees/${iterator.item.managerId}
        method: get
        condition: '{{present(iterator.item.managerId)}}'
```

### Iterator Context Reference

| Expression                   | Description                                               |
| ---------------------------- | --------------------------------------------------------- |
| `$.iterator.item`            | Current item from the iterated array                      |
| `$.iterator.index`           | Current iteration index (0-based)                         |
| `$.iterator.current`         | Output from the previous step function in `stepFunctions` |
| `${iterator.item}`           | String interpolation of current item (for URLs)           |
| `${iterator.item.fieldName}` | Nested field from current item                            |

***

## Expression Syntax

The Falcon engine supports three expression formats for dynamic values. For the **complete expression language reference** including all built-in functions, operators, and detailed examples, see the [Expression Language](/guides/connector-engine/expression-language) page.

### JSONPath (Preferred)

Direct data access. **Use for any direct reference.**

```yaml theme={null}
# Credentials
token: $.credentials.apiKey

# Inputs
value: $.inputs.userId

# Step output
dataSource: $.steps.fetch_users.output.data
```

### String Interpolation (`${...}`)

Use for **embedding values within strings**.

```yaml theme={null}
# URL path parameters
url: /users/${inputs.id}

# Dynamic domains
baseUrl: https://${credentials.subdomain}.api.provider.com
```

### JEXL Expressions (`'{{...}}'`)

Use for **conditional logic and transformations**. Must be in single quotes.

```yaml theme={null}
# Conditionals
condition: '{{present(inputs.filter)}}'

# Default values
value: '{{inputs.limit ?? 100}}'

# Ternary operations
value: '{{$.count > 0 ? $.count : 0}}'
```

**Common functions:** `present()`, `missing()`, `includes()`, `join()`, `capitalize()`, `truncate()`, `regexMatch()`, `now()` — see [full reference](/guides/connector-engine/expression-language#built-in-functions).

***

## Conditional Arguments

Include arguments only when conditions are met:

```yaml theme={null}
args:
  - name: filter
    value: '{{inputs.filter}}'
    in: query
    condition: '{{present(inputs.filter)}}'

  - name: updated_since
    value: $.inputs.updated_after
    in: query
    condition: '{{present(inputs.updated_after)}}'

  - name: include_inactive
    value: "true"
    in: query
    condition: '{{inputs.include_inactive == true}}'
```

***

## Result

Define the action's response output.

**Read operations:**

```yaml theme={null}
result:
  data: $.steps.fetch_users.output.data
```

**Write operations:**

```yaml theme={null}
result:
  message: User created successfully
  data:
    id: '{{inputs.id}}'
```

**With pagination info:**

```yaml theme={null}
result:
  data: $.steps.list_users.output.data
  next: $.steps.list_users.output.next
```

***

## Field Configs (Unified Actions)

For unified actions (those with a `schema` field), `fieldConfigs` map provider response fields to StackOne's standardized schema:

```yaml theme={null}
- actionId: list_users
  actionType: list
  schema: users
  fieldConfigs:
    - targetFieldKey: id
      expression: $.accountId
      type: string
    - targetFieldKey: email
      expression: $.emailAddress
      type: string
    - targetFieldKey: status
      expression: $.userStatus
      type: enum
      enumMapper:
        matcher:
          - matchExpression: '{{$.userStatus == "ACTIVE"}}'
            value: active
          - matchExpression: '{{$.userStatus == "SUSPENDED"}}'
            value: inactive
```

For built-in enum matchers and full field config options, see the [YAML Reference — map\_fields](/guides/connector-engine/connector-yaml-reference#map_fields).

***

## Rate Limiting

Configure request throttling:

```yaml theme={null}
rateLimit:
  mainRatelimit: 10    # Max requests per second
```

***

## Validation

Validate connector files using the CLI:

```bash theme={null}
npm install -g @stackone/cli

stackone validate path/to/connector.s1.yaml
```

***

## Complete Example

```yaml theme={null}
# provider.connector.s1.yaml
StackOne: 1.0.0
info:
  title: Acme HR
  key: acme_hr
  version: 1.0.0
  assets:
    icon: https://stackone-logos.com/api/acme_hr/filled/png
  description: HR management platform

baseUrl: https://api.acme.com/v2

rateLimit:
  mainRatelimit: 10

authentication:
  - custom:
      type: custom
      label: API Key
      authorization:
        type: bearer
        token: $.credentials.apiKey
      configFields:
        - key: apiKey
          label: API Key
          type: password
          required: true
          secret: true
      environments:
        - key: production
          name: Production
      testActionsIds:
        - list_employees

actions:
  - $ref: acme_hr.employees
```

```yaml theme={null}
# provider.employees.s1.partial.yaml
- actionId: list_employees
  categories:
    - hris
  actionType: custom
  label: List Employees
  description: Get all employees with pagination
  context: https://api.acme.com/docs/employees
  inputs:
    - name: page_size
      type: number
      in: query
      required: false
      description: Results per page (max 100)
    - name: status
      type: string
      in: query
      required: false
      description: Filter by status (active, inactive)
  steps:
    - stepId: fetch_employees
      stepFunction:
        functionName: paginated_request
        parameters:
          url: /employees
          method: get
          response:
            dataKey: data
            nextKey: pagination.next_cursor
          iterator:
            key: cursor
            in: query
          args:
            - name: limit
              value: '{{inputs.page_size || 100}}'
              in: query
            - name: status
              value: '{{inputs.status}}'
              in: query
              condition: '{{present(inputs.status)}}'
  result:
    data: $.steps.fetch_employees.output.data

- actionId: get_employee
  categories:
    - hris
  actionType: custom
  label: Get Employee
  description: Get employee by ID
  context: https://api.acme.com/docs/employees/{id}
  inputs:
    - name: id
      type: string
      in: path
      required: true
      description: Employee ID
  steps:
    - stepId: fetch_employee
      stepFunction:
        functionName: request
        parameters:
          url: /employees/${inputs.id}
          method: get
  result:
    data: $.steps.fetch_employee.output.data
```

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Expression Language" icon="function" href="/guides/connector-engine/expression-language">
    Full reference for JSONPath, JEXL, and string interpolation
  </Card>

  <Card title="YAML Reference" icon="file-code" href="/guides/connector-engine/connector-yaml-reference">
    Complete property reference with impact analysis
  </Card>

  <Card title="Browse Examples" icon="code" href="https://github.com/StackOneHQ/connectors-template/">
    See real connector implementations
  </Card>

  <Card title="StackOne Agent" icon="robot" href="/guides/connector-engine/stackone-agent">
    Generate connectors with AI assistance
  </Card>
</CardGroup>
