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

# Act

`POST /act` is Membrane's unified entry point for running an action through a connection. See the [Actions guide](/docs/how-membrane-works/actions) for the conceptual walkthrough — this page is the endpoint reference.

## Dispatch styles

Exactly **one** of `id`, `key`, `api`, or `code` per call. Sending more than one returns `400`.

| Field  | Style         | When to use                                                                             |
| ------ | ------------- | --------------------------------------------------------------------------------------- |
| `api`  | Inline `api`  | Make an ad-hoc HTTP request through the connection's auth and base URL.                 |
| `code` | Inline `code` | Run a JavaScript snippet in a sandbox with a pre-wired authenticated `membrane` client. |
| `key`  | Reusable      | Run a saved (workspace- or integration-level) action by its stable key.                 |
| `id`   | Reusable      | Run a catalog action or a saved action by its Membrane ID.                              |

## Resolving a connection

Every dispatch needs a connection. Membrane resolves one in this order:

1. `connectionId` — direct.
2. `connectionKey` — look up by key.
3. `integrationId` or `integrationKey` — use that integration's default connection.
4. Workspace default connection.

Reusable-action dispatches that target a connection-scoped or integration-scoped action use the action's own scope automatically — the body fields above only kick in when the action's scope doesn't already resolve a connection.

For inline dispatches (`api` / `code`), the connection must resolve to something — otherwise the request returns `400`.

## Request body

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

  ```json code theme={null}
  {
    "connectionKey": "hubspot-prod",
    "code": "module.exports = async ({ input, membrane }) => ({ ok: true })",
    "input": {}
  }
  ```

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

  ```json id theme={null}
  {
    "id": "action_abc",
    "connectionKey": "hubspot-prod",
    "input": { "email": "jane@example.com" },
    "meta": { "source": "support-ticket-1234" }
  }
  ```
</RequestExample>

| Field            | Type   | Description                                                                                                 |
| ---------------- | ------ | ----------------------------------------------------------------------------------------------------------- |
| `api`            | object | Inline HTTP spec — `{ method, path, body?, headers?, query? }`.                                             |
| `code`           | string | Inline JS module body, executed in a sandbox.                                                               |
| `key`            | string | Action key. Scope with `integrationKey`/`integrationId`/`connectionId` if non-unique.                       |
| `id`             | string | Action ID. Mutually exclusive with `key` / `api` / `code`.                                                  |
| `connectionId`   | string | Connection to run against. See [resolution priority](#resolving-a-connection).                              |
| `connectionKey`  | string | Connection key alternative to `connectionId`.                                                               |
| `integrationId`  | string | Integration ID — used to scope `key` lookups or pick a default connection.                                  |
| `integrationKey` | string | Integration key alternative to `integrationId`.                                                             |
| `input`          | object | Action input. For reusable-action dispatches, validated against the action's `inputSchema`.                 |
| `meta`           | object | Arbitrary metadata stored on the resulting [Action Run Log](/reference/workspace-elements/action-run-logs). |

## Response

```json theme={null}
{
  "output": { "id": "12345", "email": "jane@example.com" },
  "actionRunId": "<action-run-id>"
}
```

Every response — success or failure — carries an `actionRunId`. Pass it to [`GET /action-run-logs/{id}`](/reference/workspace-elements/action-run-logs) to inspect the resolved action, mapped input, raw HTTP exchange, and any errors. On failure the body still includes `actionRunId` alongside the error.

## Replay from a run log

Every action run log carries an `action` field — the complete `/act` body that was used. Pass it back unchanged to re-run 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"
```

The snapshot is the source of truth for "what ran". Top-level `input` and `connectionId` on the run log are deprecated — read them from `action` instead.

## Legacy: `POST /actions/{selector}/run`

`POST /actions/{selector}/run` is the older endpoint for running a saved action. It still works for existing callers but is **deprecated** — `/act` covers all the same cases plus inline `api` and `code` dispatch.

| Before                                           | After                                                                                     |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------- |
| `POST /actions/<id>/run` body: `{ ...input }`    | `POST /act` body: `{ "id": "<id>", "input": {...}, "connectionKey": "..." }`              |
| `POST /actions/<key>/run?connectionId=<id>`      | `POST /act` body: `{ "key": "<key>", "connectionId": "<id>", "input": {...} }`            |
| Ad-hoc HTTP via a custom `run-javascript` action | `POST /act` body: `{ "api": { "method": "...", "path": "..." }, "connectionKey": "..." }` |

Use `/act` for new code.


## OpenAPI

````yaml POST /act
openapi: 3.0.0
info:
  title: Membrane API
  description: API documentation for Membrane Engine
  version: '1.0'
  contact: {}
servers:
  - url: https://api.getmembrane.com
security:
  - bearer: []
tags: []
paths:
  /act:
    post:
      tags:
        - Act
      summary: Run an action
      operationId: act
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ActRequestDto'
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ActResponseDto'
components:
  schemas:
    ActRequestDto:
      type: object
      properties:
        id:
          description: ID of the action to run.
          type: string
        key:
          description: >-
            Key of the action to run. If the same key exists across multiple
            integrations, also pass `integrationId`, `integrationKey`, or
            `connectionId` so we know which one you mean.
          type: string
        api:
          description: >-
            Inline HTTP request spec, sent through the resolved connection's
            auth layer and base URL. Pair with `connectionId`, `connectionKey`,
            `integrationId`, or `integrationKey` to pick the connection.
          type: object
          properties:
            method:
              type: string
              enum:
                - GET
                - POST
                - PATCH
                - PUT
                - DELETE
              description: HTTP method to use.
            path:
              description: >-
                Path appended to the connection's base URL, e.g. `/v2/users/me`.
                Required.
              type: string
            body:
              description: Request body. For JSON APIs, pass a plain object.
            headers:
              description: Additional HTTP headers.
              type: object
              additionalProperties:
                type: string
            query:
              description: Query-string parameters.
              type: object
              additionalProperties:
                anyOf:
                  - type: string
                  - type: number
                  - type: boolean
          required:
            - method
        code:
          description: >-
            Inline JavaScript executed in a sandbox. The module must export a
            function that receives `{ input, membrane, ... }`. Its return value
            becomes the action output.
          type: string
        integrationId:
          description: >-
            ID of the integration to run the action on. When `key` is provided,
            looks up the action within this integration. When no connection is
            specified, runs against this integration's default connection.
          type: string
        integrationKey:
          description: >-
            Key of the integration to run the action on. When `key` is provided,
            looks up the action within this integration. When no connection is
            specified, runs against this integration's default connection.
          type: string
        connectionId:
          description: >-
            ID of the connection to run the action against. If a
            connection-level version of the action exists on this connection,
            that version is used; otherwise the integration-level or universal
            action is used.
          type: string
        connectionKey:
          description: >-
            Key of the connection to run the action against. Use when you have a
            stable key for the connection instead of an ID.
          type: string
        input:
          description: Input passed to the action, matching its input schema.
        meta:
          description: Arbitrary metadata stored on the action run log.
          type: object
          additionalProperties:
            type: object
      additionalProperties: false
    ActResponseDto:
      type: object
      properties:
        output:
          type: object
        actionRunId:
          type: string
  securitySchemes:
    bearer:
      scheme: bearer
      bearerFormat: JWT
      type: http

````