# Step Function — Request

Use `functionName: request` for all standard REST and GraphQL operations.

## Structure

```yaml
steps:
  - stepId: step_id           # snake_case — referenced in result pattern
    description: Short description of what the step does
    stepFunction:
      functionName: request
      parameters:
        url: /endpoint/path   # relative to connector baseUrl; use ${inputs.field} for path params
        method: get           # get | post | put | patch | delete
        args:
          - name: paramName
            value: $.inputs.paramName
            in: query         # query | body | headers
            condition: '{{present(inputs.paramName)}}'  # for optional params
```
**For args configuration — read `references/args-config.md`.**

## Step Fields

| Field | Required | Notes |
| :--- | :--- | :--- |
| `stepId` | Yes | snake_case — must match reference in `result:\n  data: $.steps.{stepId}.output.data` |
| `description` | Yes | Short description of what the step does |
| `stepFunction.functionName` | Yes | Always `request` for REST |
| `stepFunction.parameters.url` | Yes | Endpoint path — use `${inputs.field}` for path params |
| `stepFunction.parameters.method` | Yes | `get`, `post`, `put`, `patch`, `delete` |
| `stepFunction.parameters.args` | No | Parameters sent to the provider. **For args configuration — read `references/args-config.md`.** |

## Parameters

| Parameter | Required | Notes |
| :--- | :--- | :--- |
| `url` | Yes | Endpoint path — supports string interpolation |
| `method` | Yes | HTTP method |
| `args` | No | Request parameters — see `args-config.md` |
| `authorization` | No | Override authentication if requried for this action only |

## URL String Interpolation

Use `${...}` for path parameters — never put path params in args:

```yaml
url: /users/${inputs.userId}
url: /teams/${inputs.teamId}/channels/${inputs.channelId}/messages\
```

## Authorization Override

**⚠️ IMPORTANT**: Connector-level auth is used by default. Only use `authorization` when you need to override or disable it for a specific request.

**Use cases:**
- Connector-level auth is `type: none` but this endpoint needs auth
- Different endpoint needs a different auth method
- Endpoint requires no authentication

### Disable Auth

```yaml
stepFunction:
  functionName: request
  parameters:
    url: /public/status
    method: get
    authorization:
      type: none
```

### Override with API Key Header

```yaml
stepFunction:
  functionName: request
  parameters:
    url: /api/data
    method: get
    authorization:
      type: apiKey
      key: X-API-Key
      value: $.credentials.apiKey
```

## Complete Examples

### GET with API Key Auth Header

```yaml
steps:
  - stepId: list_approvals
    description: Retrieve pending approval requests
    stepFunction:
      functionName: request
      parameters:
        url: /approvals
        method: get
        args:
          - name: X-SmartToken  # non-Bearer API key — from $.credentials.<key-name>
            value: $.credentials.apiKey
            in: headers
            condition: '{{present(credentials.apiKey)}}'
          - name: pageId
            value: $.inputs.pageId
            in: query
            condition: '{{present(inputs.pageId)}}'
```

### POST with Path Param and Body

```yaml
steps:
  - stepId: create_application
    description: Create new candidate application
    stepFunction:
      functionName: request
      parameters:
        url: /postings/${inputs.postingId}/candidates
        method: post
        args:
          - name: firstName
            value: $.inputs.firstName
            in: body
          - name: answers        # top-level only — nested properties included automatically
            value: $.inputs.answers
            in: body
            condition: '{{present(inputs.answers)}}'
          - name: message
            value: $.inputs.message
            in: body
            condition: '{{present(inputs.message)}}'
```

### GET with Special-Character Query Params (OData)

```yaml
steps:
  - stepId: fetch_messages
    description: Fetch channel messages
    stepFunction:
      functionName: request
      parameters:
        url: /teams/${inputs.teamId}/channels/${inputs.channelId}/messages
        method: get
        args:
          - name: '{{"$top"}}'
            value: $.inputs.top
            in: query
            condition: '{{present(inputs.top)}}'
          - name: '{{"$filter"}}'
            value: $.inputs.filter
            in: query
            condition: '{{present(inputs.filter)}}'
```

### GET with Query Params and Filters

```yaml
steps:
  - stepId: fetch_users
    description: Fetch users with filters
    stepFunction:
      functionName: request
      parameters:
        url: /users
        method: get
        args:
          - name: limit
            value: $.inputs.limit
            in: query
            condition: '{{present(inputs.limit)}}'
          - name: offset
            value: $.inputs.offset
            in: query
            condition: '{{present(inputs.offset)}}'
          - name: status
            value: $.inputs.status
            in: query
            condition: '{{present(inputs.status)}}'
```

### PATCH with Optional Body Fields

```yaml
steps:
  - stepId: update_user
    description: Update user by ID
    stepFunction:
      functionName: request
      parameters:
        url: /users/${inputs.userId}
        method: patch
        args:
          - name: first_name
            value: $.inputs.firstName
            in: body
            condition: '{{present(inputs.firstName)}}'
          - name: last_name
            value: $.inputs.lastName
            in: body
            condition: '{{present(inputs.lastName)}}'
```

### DELETE

```yaml
steps:
  - stepId: delete_user
    description: Delete user by ID
    stepFunction:
      functionName: request
      parameters:
        url: /users/${inputs.userId}
        method: delete
```

## Critical Rules

- ✅ Always include step `description`
- ✅ `stepId` must match the reference in `result:\n  data: $.steps.{stepId}.output.data`
- ✅ Use `${inputs.field}` for path params in URL — never put them in args
- ✅ Use `condition: '{{present(inputs.field)}}'` for all optional args
- ✅ Credential args must always have a `condition` check
- ❌ Never use more than one step per action
- ❌ Never use `body:` field directly — always use `args`
