Skip to main content

Quick Start

The most common pattern: create a toolset and give your agent search and execute tools. The agent discovers and runs tools on demand.
import { StackOneToolSet } from "@stackone/ai";

// getTools returns the tool_search + tool_execute meta tools, so search must be
// enabled on the toolset (pass search: {} for defaults).
const toolset = new StackOneToolSet({ search: { method: "auto" } });

// Your agent gets 2 tools: tool_search + tool_execute
const tools = toolset.getTools({ accountIds: ["your-account-id"] });
const openaiTools = tools.toOpenAI();
Pass openaiTools to any OpenAI-compatible model and the agent will search for relevant tools, then execute them automatically. See the OpenAI integration guide for a full agent loop.

Fetch Tools

When you need specific tools instead of search and execute:
const tools = await toolset.fetchTools({ accountIds: ["your-account-id"] });
const openaiTools = tools.toOpenAI();
// Filter by providers
const byProviders = await toolset.fetchTools({
  providers: ["hibob", "workday"],
  accountIds: ["your-account-id"],
});

// Filter by actions with exact match
const byActions = await toolset.fetchTools({
  actions: ["hibob_list_employees", "hibob_create_employees"],
  accountIds: ["your-account-id"],
});

// Filter by actions with glob patterns
const byGlob = await toolset.fetchTools({
  actions: ["*_list_*"],
  accountIds: ["your-account-id"],
});

// Combine multiple filters
const combined = await toolset.fetchTools({
  providers: ["hibob"],
  actions: ["*_list_*"],
  accountIds: ["your-account-id"],
});
See Tool Filtering for the full reference.
// Set accounts on the toolset for all subsequent calls
toolset.setAccounts(["account-123", "account-456"]);
const tools = await toolset.fetchTools();

// Or pass account IDs per request
const toolsDirect = await toolset.fetchTools({
  accountIds: ["account-123", "account-456"],
});

// Loop over customer accounts dynamically
const customerAccounts = ["account-1", "account-2", "account-3"];

for (const accountId of customerAccounts) {
  const tools = await toolset.fetchTools({
    actions: ["workday_list_workers"],
    accountIds: [accountId],
  });
  const employeeTool = tools.getTool("workday_list_workers");
  if (employeeTool) {
    const employees = await employeeTool.execute({});
    console.log(`Found employees for ${accountId}`);
  }
}

Tool Execution

Direct execution is useful for testing and debugging. In production, your agent framework handles tool calls automatically.
const tools = await toolset.fetchTools({ accountIds: ["your-account-id"] });
const employeeTool = tools.getTool("workday_list_workers");

if (employeeTool) {
  const result = await employeeTool.execute({
    query: { limit: 10 },
  });
  console.log(result);
}
Actions that download a file (for example googledrive_unified_download_file, documents_download_file, or any *_unified_download_file) return raw bytes plus metadata, not parsed JSON. The SDK decides from the response Content-Type: JSON is parsed as usual, and anything else is treated as a file download. Because execute() is typed to return a JSON object, use the exported isBinaryDownloadResult guard to narrow the result to the file shape.
import { writeFileSync } from "node:fs";
import { isBinaryDownloadResult } from "@stackone/ai";

const tools = await toolset.fetchTools({
  actions: ["googledrive_*"],
  accountIds: ["your-account-id"],
});
const download = tools.getTool("googledrive_unified_download_file");

if (download) {
  const result = await download.execute({ id: "file-id" });

  // isBinaryDownloadResult narrows result so content is a Buffer (no cast) and
  // confirms this was a file download rather than a JSON response.
  if (isBinaryDownloadResult(result)) {
    writeFileSync(result.fileName ?? "download.bin", result.content);
  }
}
The narrowed result describes the file:
KeyTypeDescription
contentBufferRaw file bytes. Not JSON-serializable (see note).
contentTypestringFile MIME type (for example application/pdf), or application/octet-stream.
statusCodenumberHTTP status of the download response.
headersobjectResponse headers.
fileNamestring | nullFilename from Content-Disposition (RFC 5987 filename* aware), else null.
content is a Buffer and is not JSON-serializable. If you forward tool results to an LLM (or anything that re-serializes to JSON), handle or strip the content key. For example, base64-encode it on the LLM-facing path.

Environment Configuration

export STACKONE_API_KEY=your_api_key
Account IDs are passed per-request when fetching tools or via getTools({ accountIds: [...] }).

Next Steps