> This page is for Agent Studio.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.moveworks.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.moveworks.com/_mcp/server.

# Build Focused Actions

An action is one reusable executable operation. An **HTTP action** represents one HTTP request. Other action types cover code, model work, platform capabilities, and backend composition.

## Choose the Action Type

| Action type     | Use it for                                                |
| --------------- | --------------------------------------------------------- |
| HTTP action     | Call one REST or SOAP operation                           |
| Script action   | Apply focused Python logic or transformation              |
| Built-in action | Use a capability provided by Moveworks                    |
| LLM action      | Extract, classify, or generate unstructured content       |
| Compound action | Coordinate several backend operations behind one contract |

Do not model every action as an API call. Keep the name aligned with the operation it actually performs.

## Step 1: Define Typed Input Arguments

Input arguments make an action reusable. Define the values the caller must provide without coupling the action to a specific conversation.

For a `Get feature requests` HTTP action:

| Argument | Type      | Purpose                   |
| -------- | --------- | ------------------------- |
| `status` | `string`  | Optional status filter    |
| `limit`  | `integer` | Maximum records to return |

For an `Update feature request` HTTP action:

| Argument             | Type     | Purpose                     |
| -------------------- | -------- | --------------------------- |
| `feature_request_id` | `string` | Stable downstream record ID |
| `new_status`         | `string` | Allowed target state        |

> **Keep Conversation Out of the Action Contract**
>
> Name arguments for business data, not for where the data came from. A slot, webhook payload, schedule body, compound action, or another process can supply the same action input.

## Step 2: Configure One HTTP Operation

An HTTP action defines:

**`Connector`** `HTTP connector` — required

Supplies the base URL and authentication configuration.

---

**`Method`** `GET | POST | PUT | PATCH | DELETE` — required

Matches the downstream API operation.

---

**`Endpoint`** `path` — required

Begins with `/` and is appended to the connector base URL.

---

**`Headers`** `key-value map`

Adds operation-specific headers such as content type, version, tenant, or instance.

---

**`Query Parameters`** `key-value map`

Adds filtering, pagination, sorting, or operation flags.

---

**`Request Body`** `JSON, XML, form, or binary`

Sends the payload required by write operations.

---

**`Response Schema`** `schema`

Keeps only the fields the caller needs and establishes a stable output contract.

---

## Build Along: Create the PurpleSuite Actions

Use the explorer to inspect the current Community API contract. It reads public catalog and OpenAPI metadata, then translates the selected operation into an Agent Studio action outline. It never requests credentials or executes the operation.

Create these three HTTP actions with the connector from the previous chapter:

| Action                               | Method and endpoint                                                           | Inputs                                            | Purpose                           |
| ------------------------------------ | ----------------------------------------------------------------------------- | ------------------------------------------------- | --------------------------------- |
| `List PurpleSuite feature requests`  | `GET /api/purple-suite/community/feature_requests`                            | `$filter`, `$select`, and `$top` query parameters | Supplies live resolver candidates |
| `Get PurpleSuite feature request`    | `GET /api/purple-suite/community/feature_requests/{{{feature_request_id}}}`   | `feature_request_id`                              | Verifies the final record state   |
| `Update PurpleSuite feature request` | `PATCH /api/purple-suite/community/feature_requests/{{{feature_request_id}}}` | `feature_request_id`, `new_status`                | Changes one selected request      |

Add `X-Instance-ID` as an action header for all three operations. For the update action, map a JSON body with only the field being changed:

```json
{
  "currentStatus": "{{{new_status}}}"
}
```

Configure the list action with the query parameters used by the dynamic resolver:

| Query parameter | Value                               |
| --------------- | ----------------------------------- |
| `$filter`       | `currentStatus ne 'Planned'`        |
| `$select`       | `id,name,currentStatus,productArea` |
| `$top`          | `10`                                |

Run the three actions in the same order the complete plugin uses:

1. Run `List PurpleSuite feature requests` and save one returned record's `id`, `name`, and original `currentStatus`.
2. Run `Get PurpleSuite feature request` with that ID and verify the same record is returned.
3. Run `Update PurpleSuite feature request` with the ID and `new_status: Planned`.
4. Run the get action again and verify `currentStatus` is `Planned`.
5. Restore the original status when appropriate for your development instance.

Your checkpoint is three independently tested actions with stable, minimal response schemas.

## Step 3: Place Variables Safely

HTTP actions can reference inputs and supported runtime values in the endpoint, headers, query parameters, body, and JWT claims.

#### Escaped Mustache

Use double braces when you need escaped string substitution:

```text
{{query}}
```

Escaping can change characters such as `@`, `/`, quotes, or JSON punctuation.

#### Raw Mustache

Use triple braces for the common HTTP action pattern when the downstream API needs the value without URL or HTML escaping:

```text
/feature_requests/{{{feature_request_id}}}
```

```json
{
  "currentStatus": "{{{new_status}}}"
}
```

Validate the value through its type, resolver, or DSL policy before placing it into a request.

#### Data Mapper

Use Data Mapper when the request contains structured values, arrays, nested objects, filtering, or conditional fields:

```yaml
employee:
  id: employee.id
  email: employee.email
tags:
  MAP():
    items: selected_tags
    converter:
      value: item
```

Data Mapper preserves types. Mustache substitution produces strings.

> **Older Examples Use Mixed Mustache Styles**
>
> Some existing quickstarts use double braces for HTTP values. Follow the current HTTP action guidance: use triple braces for raw request substitution, and use Data Mapper when the value must remain a list, object, number, or boolean.

## Step 4: Use Runtime User Data Deliberately

In user-triggered execution, an HTTP action can reference supported user attributes through `meta_info.user`.

```text
{{{meta_info.user.email_addr}}}
```

Use the bare `meta_info.user.email_addr` path only in Data Mapper or DSL contexts. Do not assume that user context exists in webhook or scheduled execution. Pass identity as an explicit input when backend work needs it.

Use `meta_info.action_instance_id` when the downstream API supports an idempotency key.

## Step 5: Shape the Response Early

Every field you keep becomes part of a downstream contract. Prefer:

```json
{
  "id": "FR-1042",
  "name": "Bulk edit requests",
  "current_status": "Planned",
  "product_area": "Admin"
}
```

Avoid passing:

```json
{
  "raw_record": {
    "internal_metadata": {},
    "debug": {},
    "audit_history": [],
    "unused_fields": []
  }
}
```

There are three useful pruning boundaries:

1. The HTTP action **Response Schema** removes fields before returning to its caller.
2. A compound action's **`return.output_mapper`** controls its final return.
3. A conversation action activity's **Output Mapping** controls what enters the conversation process and reasoning context.

## Step 6: Test the Action in Isolation

Provide example values for every input argument and test:

* A successful response.
* No matching data.
* Invalid and boundary values.
* Unauthorized and forbidden responses.
* Rate limiting and timeouts.
* Malformed downstream data.
* A repeated write with the same idempotency key.

The action editor uses the currently logged-in builder for user runtime attributes. This does not prove that every end user has the same downstream access.

## Action Quality Checklist

* The name begins with a clear verb.
* The action performs one focused operation.
* Input arguments are typed and reusable.
* The endpoint path begins with `/`.
* The connector supplies secrets; descriptions and mappings do not.
* Request variables use the correct substitution or mapping method.
* The response schema includes only useful fields.
* Errors preserve enough detail for deterministic handling without exposing secrets.
* The action passes isolated tests before composition.

## Deep Dives

* [Actions](/agent-studio/actions)
* [HTTP Actions](/agent-studio/actions/http-actions)
* [HTTP Action Data Bank](/agent-studio/actions/http-actions/http-action-data-bank)
* [Data Mapper in HTTP Actions](/agent-studio/actions/http-actions/data-mapper-in-http-actions)
* [Script Actions](/agent-studio/actions/script-actions)
* [LLM Actions](/agent-studio/actions/llm-actions)

Next, [map data and context](/agent-studio/guides/plugin-building-masterclass/map-data-and-context).