Skip to main content
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.
This guide is for platform builders creating custom interfaces that display available integrations and actions to their end-users.
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:
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: [...] }
// ]

Filter Actions by Context

Filter by connector, account, or action key to get relevant actions for your UI:
const result = await stackOne.actions.listActionsMeta({
  filter: {
    connectors: "bamboohr,workday",
    accountIds: "acct_abc123",
  },
});
See the List Actions API Reference for all available filter parameters.

Understanding Action Schema

The response is grouped by provider, with each provider containing its available actions:
{
  "data": [
    {
      "key": "sapsuccessfactors",
      "name": "SAP SuccessFactors",
      "description": "SAP SuccessFactors is a comprehensive cloud-based HCM solution...",
      "icon": "https://stackone-logos.com/api/sap-sucessfactors/filled/png",
      "version": "1.0.0",
      "categories": ["hris", "ats", "lms", "iam"],
      "authentication": [
        {
          "type": "custom",
          "label": "OAuth 2.0",
          "key": "custom"
        }
      ],
      "actions": [
        {
          "id": "sapsuccessfactors_list_employees",
          "label": "List Employees",
          "description": "Retrieve a list of all employees...",
          "schema_type": "native",
          "authentication": [...]
        },
        {
          "id": "sapsuccessfactors_get_employee",
          "label": "Get Employee",
          "description": "Retrieve detailed information about a specific employee"
        }
      ]
    }
  ],
  "next": "eyJyIjp7InAiOjI1fX0..."
}

Provider Fields

FieldDescription
keyProvider identifier (e.g., sapsuccessfactors, workday)
nameDisplay name for UI
descriptionProvider description
iconURL to provider logo
versionProvider integration version
categoriesCategories this provider supports (e.g., hris, ats, lms)
authenticationSupported authentication methods
actionsList of available actions

Action Fields

FieldDescription
idAction identifier for RPC calls
labelHuman-readable label for UI
descriptionAction description
schema_typeSchema type (e.g., native)
authenticationAuthentication methods for this specific action
operation_detailsDetailed operation schema (when include=action_details)

Building a Dynamic Action UI

Here’s how to build an interface that adapts to available actions:
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;
}

Execute Actions via RPC

Once a user selects an action, execute it with the RPC endpoint:
const result = await stackOne.actions.rpcAction({
  action: "bamboohr_list_employees",
  query: {
    pageSize: "25",
  },
  xAccountId: "customer-bamboohr",
});
The action field matches the id from the actions metadata.

Real-World Example: Integration Dashboard

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;
}