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

# Actions

An action is a single operation your agent or app performs in an external app: create a contact, send a message, list invoices, update a deal. Actions are the primary way to interact with connected apps through Membrane.

## Running actions

Running an action means calling **`/act`** — Membrane's unified entry point for operating on an external app through a connection. One endpoint, one shape, multiple surfaces:

| Way to Use | How to Run                                                                          |
| ---------- | ----------------------------------------------------------------------------------- |
| CLI        | `membrane act --connectionKey <key> --api '{"method":"POST","path":"/..."}' --json` |
| MCP        | Use the `act` tool with one of `api` / `code` / `key` / `id`                        |
| API        | [`POST /act`](/reference/workspace-elements/act) with the dispatch in the body      |
| Console    | Action → Run (test with sample input)                                               |

Every response is `{ output, actionRunId }`. On failure the body still carries `actionRunId` — feed it to [`GET /action-run-logs/{id}`](/reference/workspace-elements/action-run-logs) for the resolved action, mapped input, errors, and the raw HTTP exchange.

## What goes into `/act`

Three dispatch styles, exactly **one** per call. Pick the one that fits the work:

### `api` — inline HTTP request

A raw HTTP request sent through the connection's auth and base URL. Default building block for ad-hoc work.

```json theme={null}
{
  "connectionKey": "hubspot-prod",
  "api": {
    "method": "POST",
    "path": "/crm/v3/objects/contacts",
    "body": { "properties": { "email": "jane@example.com" } }
  }
}
```

### `code` — sandboxed JavaScript

A JS snippet run in a sandbox with an authenticated `membrane` client, `connection`, and `integration` pre-wired. Good for multi-step composites that don't map to a single HTTP call.

```json theme={null}
{
  "connectionKey": "hubspot-prod",
  "code": "module.exports = async ({ input, membrane }) => { const me = await membrane.proxy.get('/account-info'); return { portalId: me.data.portalId, ...input }; }",
  "input": { "tag": "qa" }
}
```

### Reusable action

A named action Membrane runs on your behalf. Address it by `key` when the action has one (saved actions); use `id` when it doesn't (catalog actions have no `key`). Membrane owns the vendor-specific request shape, auth scoping, and retries.

```json theme={null}
{
  "key": "create-contact",
  "integrationKey": "hubspot",
  "connectionKey": "hubspot-prod",
  "input": { "email": "jane@example.com" }
}
```

`api` and `code` always need a connection (via `connectionKey` or `connectionId`). Reusable actions route through the action's own scope, which may bind a specific connection or integration — so the connection field becomes optional when the scope already resolves one.

Input is validated against the action's `inputSchema`. Extra properties are silently ignored.

<Note>
  The legacy [`POST /actions/{selector}/run`](/reference/workspace-elements/act#legacy-post-actionsselectorrun) endpoint
  is **deprecated**. It still works for existing callers but new code should use `/act`.
</Note>

## Reusable actions

When you find yourself about to make the same `/act` call a second time, save it as a reusable action. Future calls become `{ key: "<your-key>" }` instead of the full inline spec, and the action is inspectable in the workspace later.

### Finding

Describe what you want to do and Membrane finds matching actions. You can search by intent across your workspace and connected apps.

| Way to Use | How to Find                                                                   |
| ---------- | ----------------------------------------------------------------------------- |
| CLI        | `membrane action list --connectionId <id> --intent "create a contact"`        |
| MCP        | Use the `list-actions` tool with intent parameter                             |
| API        | `GET /actions?connectionId=<id>&intent=create+a+contact`                      |
| SDK        | `membrane.actions.find({ connectionId: '<id>', intent: 'create a contact' })` |
| Console    | Actions page — browse and search                                              |

### Creating

Create actions from an intent — describe what the action should do and Membrane configures it automatically.

| Way to Use | How to Create                                                                |
| ---------- | ---------------------------------------------------------------------------- |
| CLI        | `membrane action create "create a task" --connectionId <id>`                 |
| MCP        | Use the `create-action` tool                                                 |
| API        | `POST /actions` with `{ "intent": "create a task", "connectionId": "<id>" }` |
| SDK        | `membrane.actions.create({ intent: 'create a task', connectionId: '<id>' })` |
| Console    | Actions → Create Action                                                      |

The action enters a `BUILDING` state while Membrane configures it. Use `--wait` (CLI) or `?wait=true` (API) to wait until ready.

### Updating

Update an action's configuration.

| Way to Use | How to Update                                  |
| ---------- | ---------------------------------------------- |
| API        | `PATCH /actions/<actionId>`                    |
| SDK        | `membrane.action('<actionId>').patch({ ... })` |
| Console    | Action → Edit                                  |

### Deleting

Archive an action to remove it.

| Way to Use | How to Delete                             |
| ---------- | ----------------------------------------- |
| API        | `DELETE /actions/<actionId>`              |
| SDK        | `membrane.action('<actionId>').archive()` |
| Console    | Action → Archive                          |

## Action Types

Actions map to function types that determine what happens when they run:

| Type                          | Description                                     |
| ----------------------------- | ----------------------------------------------- |
| `api-request-to-external-app` | Make API requests with automatic authentication |
| `api-request-to-your-app`     | Make an API request to your backend             |
| `run-javascript`              | Run custom JavaScript/TypeScript logic          |
| `http-request`                | Make arbitrary HTTP requests                    |

## Run logs and replay

All action runs are recorded in [Action Run Logs](/reference/workspace-elements/action-run-logs) — input, output, duration, errors, and the raw HTTP exchange.

Each log carries an `action` snapshot — the complete `/act` body that was used. POST it back to `/act` to replay the same dispatch:

```bash theme={null}
SNAPSHOT=$(curl -s https://api.integration.app/action-run-logs/<runId> \
  -H "Authorization: Bearer $TOKEN" | jq '.action')

curl -X POST https://api.integration.app/act \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "$SNAPSHOT"
```

Override `input` or `connectionKey` in the snapshot to vary the call:

```bash theme={null}
curl -X POST https://api.integration.app/act \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(echo "$SNAPSHOT" | jq '.input.email = "updated@example.com"')"
```
