> ## 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.

# Actions Metadata for Custom UIs

> Build dynamic interfaces by querying available actions, parameters, and provider capabilities

When building a platform on StackOne, you can dynamically discover what actions are available for each linked account. This enables you to build custom UIs that adapt to each provider's capabilities.

<Info>
  This guide is for **platform builders** creating custom interfaces that display available integrations and actions to their end-users.
</Info>

Instead of hardcoding integration capabilities, query the `/actions` endpoint to dynamically determine what's available.

## List all available actions

Use `GET /actions` to retrieve action metadata:

<Tabs>
  <Tab title="TypeScript SDK">
    ```typescript theme={null}
    import { StackOne } from "@stackone/stackone-client-ts";

    const stackOne = new StackOne({
      security: {
        username: process.env.STACKONE_API_KEY!,
        password: "",
      },
    });

    const result = await stackOne.actions.listActionsMeta({});

    // Result contains providers with their available actions
    // result.actionsMetaPaginated?.data = [
    //   { key: "bamboohr", name: "BambooHR", actions: [...] },
    //   { key: "salesforce", name: "Salesforce", actions: [...] }
    // ]
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl "https://api.stackone.com/actions" \
      -u "$STACKONE_API_KEY:"
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests
    import base64

    api_key = "v1.eu1.xxxxx"
    headers = {
        "Authorization": f"Basic {base64.b64encode(f'{api_key}:'.encode()).decode()}"
    }

    response = requests.get(
        "https://api.stackone.com/actions",
        headers=headers
    )

    providers = response.json()["data"]
    ```
  </Tab>
</Tabs>

***

## Filter actions by context

Filter by connector, account, or action key to get relevant actions for your UI:

<Tabs>
  <Tab title="TypeScript SDK">
    ```typescript theme={null}
    const result = await stackOne.actions.listActionsMeta({
      filter: {
        connectors: "bamboohr,workday",
        accountIds: "acct_abc123",
      },
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl "https://api.stackone.com/actions?filter[connectors]=bamboohr&filter[account_ids]=acct_abc123" \
      -u "$STACKONE_API_KEY:"
    ```
  </Tab>
</Tabs>

<Tip>
  See the [List Actions API Reference](/platform/api-reference/actions/list-all-connectors-actions-metadata) for all available filter parameters.
</Tip>

## Understanding the response

Results are grouped by provider, with each provider containing its list of actions. The fields you'll use:

| Field                        | Level    | Use it for                                                               |
| ---------------------------- | -------- | ------------------------------------------------------------------------ |
| `name`, `icon`, `categories` | Provider | Display metadata for your UI                                             |
| `authentication`             | Provider | Supported authentication methods                                         |
| `actions`                    | Provider | The provider's available actions                                         |
| `id`                         | Action   | The identifier you pass to [RPC calls](#execute-actions-via-rpc)         |
| `label`, `description`       | Action   | Display-ready copy for your UI                                           |
| `operation_details`          | Action   | Full parameter schemas — returned when you pass `include=action_details` |

See the [List Actions API Reference](/platform/api-reference/actions/list-all-connectors-actions-metadata) for the complete response schema and an example response.

## Building a dynamic action UI

Here's how to build an interface that adapts to available actions:

<Tabs>
  <Tab title="TypeScript SDK">
    ```typescript theme={null}
    import { StackOne } from "@stackone/stackone-client-ts";

    const stackOne = new StackOne({
      security: {
        username: process.env.STACKONE_API_KEY!,
        password: "",
      },
    });

    async function getActionsForAccounts(accountIds: string[]) {
      const result = await stackOne.actions.listActionsMeta({
        filter: {
          accountIds: accountIds.join(","),
        },
      });

      return result.actionsMetaPaginated?.data ?? [];
    }

    // Flatten all actions across providers for display
    function getAllActions(providers: Awaited<ReturnType<typeof getActionsForAccounts>>) {
      return providers.flatMap(provider =>
        (provider.actions ?? []).map(action => ({
          ...action,
          providerKey: provider.key,
          providerName: provider.name,
        }))
      );
    }

    // Group actions by tag for UI sections
    function groupByTag(actions: ReturnType<typeof getAllActions>) {
      const grouped: Record<string, typeof actions> = {};
      for (const action of actions) {
        for (const tag of action.tags ?? []) {
          grouped[tag] = grouped[tag] || [];
          grouped[tag].push(action);
        }
      }
      return grouped;
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from collections import defaultdict
    import requests
    import base64
    import os

    def get_actions_for_accounts(account_ids: list[str]) -> list[dict]:
        api_key = os.environ["STACKONE_API_KEY"]
        headers = {
            "Authorization": f"Basic {base64.b64encode(f'{api_key}:'.encode()).decode()}"
        }

        response = requests.get(
            "https://api.stackone.com/actions",
            params={"filter[account_ids]": ",".join(account_ids)},
            headers=headers
        )
        return response.json()["data"]

    def get_all_actions(providers: list[dict]) -> list[dict]:
        """Flatten all actions across providers."""
        actions = []
        for provider in providers:
            for action in provider.get("actions", []):
                actions.append({
                    **action,
                    "provider_key": provider.get("key"),
                    "provider_name": provider.get("name"),
                })
        return actions

    def group_by_tag(actions: list[dict]) -> dict[str, list[dict]]:
        """Group actions by their tags."""
        grouped = defaultdict(list)
        for action in actions:
            for tag in action.get("tags", []):
                grouped[tag].append(action)
        return dict(grouped)
    ```
  </Tab>
</Tabs>

## Execute actions via RPC

Once a user selects an action, execute it by passing the action's `id` as the `action` field on the RPC endpoint. See [RPC/HTTP](/embed/call-actions/rpc-http) for the call shape and the [Actions RPC reference](/platform/api-reference/actions/make-an-rpc-call-to-an-action) for all parameters and code samples.

## Real-world example: integration dashboard

```typescript theme={null}
import { StackOne } from "@stackone/stackone-client-ts";

const stackOne = new StackOne({
  security: {
    username: process.env.STACKONE_API_KEY!,
    password: "",
  },
});

async function renderIntegrationDashboard(customerId: string) {
  // 1. Get customer's linked accounts
  const { linkedAccounts } = await stackOne.accounts.listLinkedAccounts({
    originOwnerId: customerId,
  });

  // 2. Get available actions for these accounts
  const accountIds = (linkedAccounts ?? []).map(a => a.id).filter(Boolean);
  const actionsResult = await stackOne.actions.listActionsMeta({
    filter: {
      accountIds: accountIds.join(","),
    },
  });

  const providers = actionsResult.actionsMetaPaginated?.data ?? [];

  // 3. Build dashboard data with actions grouped by tag
  return {
    accounts: linkedAccounts,
    providers: providers.map(provider => ({
      key: provider.key,
      name: provider.name,
      icon: provider.icon,
      actionsByTag: groupByTag(provider.actions ?? []),
      totalActions: provider.actions?.length ?? 0,
    })),
  };
}

function groupByTag(actions: { tags?: string[] }[]) {
  const grouped: Record<string, typeof actions> = {};
  for (const action of actions) {
    for (const tag of action.tags ?? []) {
      grouped[tag] = grouped[tag] || [];
      grouped[tag].push(action);
    }
  }
  return grouped;
}
```

## Related

<CardGroup cols={2}>
  <Card title="Actions RPC" icon="bolt" href="/platform/api-reference/actions/make-an-rpc-call-to-an-action">
    Execute actions programmatically
  </Card>

  <Card title="List Actions API" icon="code" href="/platform/api-reference/actions/list-all-connectors-actions-metadata">
    Full API reference for actions metadata
  </Card>

  <Card title="Multi-Tenant Accounts" icon="users" href="/features/multi-tenant-accounts">
    Segment accounts by customer
  </Card>

  <Card title="Connector Metadata" icon="puzzle-piece" href="/platform/api-reference/connectors/list-connector-meta-information-legacy">
    Get connector logos and branding
  </Card>
</CardGroup>
