Steps
Sequential API calls that fetch or modify data. Each step can reference data from previous steps.
Tools in superglue are reusable workflows that you can execute on-demand, schedule, or trigger via webhooks. Each tool consists of sequential steps with built-in data transformations, loops, and error handling.
Learn more about how tools fit into the bigger picture in our core concepts page.
The fastest way to create a tool is by talking to our agent. Describe what you want to accomplish and the agent will build the tool for you.
Simple example:
"Create a tool that fetches all active customers from Stripe"superglue will:
Complex example:
"Create a tool that loops through all contacts in HubSpot,filters those with email domains matching @company.com,and updates their lifecycle stage to 'customer'"The agent can build multi-step tools with:
Build tools in the UI:
Navigate to tools
Go to Tools in your superglue dashboard and click “Create Tool”
Select systems
Choose which systems this tool will use
Add instruction
Describe what the tool should do in natural language. superglue will build the workflow steps automatically.
Test and save
Run the tool with sample data to verify it works as expected. See debugging tools for troubleshooting.
Use the REST SDK to run tools you’ve already created:
npm install @superglue/clientConfigure and run a tool:
import { configure, runTool, getTool, listTools } from "@superglue/client";
// Configure the SDK with your API endpoint and tokenconfigure({ baseUrl: "https://api.superglue.cloud", // or your self-hosted URL token: "your_api_token"});
// List available toolsconst { data: tools } = await listTools();console.log(tools);
// Get a specific toolconst { data: tool } = await getTool("my-tool-id");
// Run a tool with input payloadconst { data: run } = await runTool("my-tool-id", { inputs: { userId: "user_123", startDate: "2024-01-01" }, credentials: { stripe_api_key: "sk_live_xxx" }});
console.log(run.data); // Tool execution resultEvery tool consists of:
Steps
Sequential API calls that fetch or modify data. Each step can reference data from previous steps.
Transformations
JavaScript functions that shape the step inputs and the final output. Ensures tool results adhere to response schemas.
Variables
Access data from previous steps, credentials, and input payload using <<variable>> syntax.
Each step in a tool represents a single API call with the following configuration:
{ id: "stepId", // Unique identifier for this step instruction: "Fetch customer data from Stripe", // Human-readable description dataSelector: "(sourceData) => { return [\"one\", \"two\"]}", // The data selector for the current step config: { systemId: "stripe", // Which system to use method: "POST", // HTTP method url: "https://api.stripe.com/v1/customers", // Full API endpoint URL queryParams: {}, // URL query parameters headers: { "Authorization": "Bearer <<stripe_apiKey>>" }, // Custom headers body: "" // Request body }}Use <<variable>> to access dynamic values:
Access credentials:
{ headers: { "Authorization": "Bearer <<systemId_access_token>>" }}Access previous step data:
{ urlPath: "/customers/<<getCustomer.data.id>>", body: { email: "<<getCustomer.data.email>>" }}Access input payload:
{ queryParams: { user_id: "<<userId>>", date: "<<startDate>>" }}Execute JavaScript expressions:
{ body: { ids: "<<(sourceData) => JSON.stringify(sourceData.users.map(u => u.id))>>", timestamp: "<<(sourceData) => new Date().toISOString()>>", count: "<<(sourceData) => sourceData.items.length>>", uppercaseName: "<<(sourceData) => sourceData.name.toUpperCase()>>" }}Extract an array to iterate over:
{ dataSelector: `(sourceData) => { const items = sourceData.fetchItems.results || []; const excludeIds = sourceData.excludeIds || []; return items.filter(item => !excludeIds.includes(item.id)); }`;}Shape the final output of the entire tool:
{ outputTransform: `(sourceData) => { const customers = sourceData.getCustomers.data || []; const updated = sourceData.updateCustomers || [];
return { success: true, total: customers.length, updated: updated.length, results: updated.map(r => ({ id: r.currentItem.id, status: r.data.status })) }; }`;}Transform steps allow you to reshape data between API calls without making an external request. Use them when you need complex data transformations that don’t fit in a dataSelector.
{ id: "formatCustomerData", instruction: "Format customer data for the next API call", config: { type: "transform", transformCode: "(sourceData) => sourceData.getCustomers.data.map(c => ({ id: c.id, name: c.fullName, email: c.contactEmail }))" }}Transform step results are wrapped in the same { currentItem, data, success } envelope as request steps:
// In a subsequent step — access the transformed data via .data{ body: "<<(sourceData) => JSON.stringify(sourceData.formatCustomerData.data)>>";}Query databases using the postgres:// URL scheme:
{ id: "queryDatabase", config: { systemId: "postgres_db", url: "postgres://<<postgres_db_username>>:<<postgres_db_password>>@<<postgres_db_hostname>>:5432/<<postgres_db_database>>", body: { query: "SELECT * FROM users WHERE status = $1 AND created_at > $2", params: ["active", "<<(sourceData) => sourceData.startDate>>"] } }}Always use parameterized queries with $1, $2, etc. placeholders to prevent SQL injection. Provide values in the params array, which can include static values or <<>> expressions.
Execute Redis commands using the redis:// (or rediss:// for TLS) URL scheme:
{ id: "getUserProfile", config: { systemId: "redis_cache", url: "redis://<<redis_cache_username>>:<<redis_cache_password>>@<<redis_cache_host>>:6379/0", body: { command: "HGETALL", args: ["<<(sourceData) => `user:${sourceData.userId}`>>"] } }}The body takes a command string and optional args array. You can also pass an array of commands to execute them as a pipeline in a single round-trip:
body: [ { command: "GET", args: ["user:123:name"] }, { command: "HGETALL", args: ["user:123"] },];Query MongoDB using the mongodb:// (or mongodb+srv:// for Atlas/SRV) URL scheme:
{ id: "findActiveUsers", config: { systemId: "mongo_db", url: "mongodb://<<mongo_db_username>>:<<mongo_db_password>>@<<mongo_db_host>>:27017/<<mongo_db_database>>?authSource=admin", body: { collection: "users", operation: "find", filter: { status: "active" }, options: { limit: 50, sort: { createdAt: -1 } } } }}The body takes an operation (find, aggregate, insertOne, updateMany, deleteOne, and other CRUD operations) and a collection. Bodies are parsed as MongoDB Extended JSON, so { "$oid": "..." } and { "$date": "..." } resolve to ObjectId and Date. Pass an array of operations to run several in one step.
Access files on FTP servers:
{ id: "listFiles", config: { systemId: "ftp-server", url: "sftp://<<ftp-server_username>>:<<ftp-server_password>>@<<ftp-server_hostname>>:22/data", body: { operation: "list", path: "/reports" } }}Supported operations:
list - List directory contentsget - Download file (auto-parses CSV/JSON/XML)put - Upload filedelete - Delete filerename - Rename/move filemkdir - Create directoryrmdir - Remove directoryexists - Check if file existsstat - Get file metadataAutomatic retries
Failed steps can be automatically retried with exponential backoff
Validation
Graceful degradation
Handle missing data with optional chaining and defaults in transformations
Define schemas to make your tools more robust:
Input schema - Validates payload before execution:
{ "type": "object", "properties": { "userId": { "type": "string" }, "startDate": { "type": "string", "format": "date" } }, "required": ["userId"]}Response schema - Validates final output:
{ "type": "object", "properties": { "success": { "type": "boolean" }, "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "email": { "type": "string" } } } } }}