TypeScript

The official TypeScript/JavaScript SDK for SteelEngine provides full type safety and supports both Node.js and browser environments, allowing you to execute workflows programmatically from your Node.js applications, web applications, and other JavaScript environments.

The TypeScript SDK provides full type safety, async execution support, automatic rate limiting with exponential backoff, and usage tracking.

Installation

Install the SDK using your preferred package manager:

npm install @steelengine/sdk

Quick Start

Here's a simple example to get you started:

import { SteelEngineClient } from '@steelengine/sdk';

// Initialize the client
const client = new SteelEngineClient({
  apiKey: 'your-api-key-here',
  baseUrl: 'https://steelengine.com' // optional, defaults to https://steelengine.com
});

// Execute a workflow
try {
  const result = await client.executeWorkflow('workflow-id');
  console.log('Workflow executed successfully:', result);
} catch (error) {
  console.error('Workflow execution failed:', error);
}

API Reference

SteelEngineClient

Constructor

new SteelEngineClient(config: SteelEngineConfig)

Configuration:

  • config.apiKey (string): Your SteelEngine API key
  • config.baseUrl (string, optional): Base URL for the SteelEngine API (defaults to {{APP_URL}})

Methods

executeWorkflow()

Execute a workflow with optional input data.

const result = await client.executeWorkflow('workflow-id', { message: 'Hello, world!' }, {
  timeout: 30000 // 30 seconds
});

Parameters:

  • workflowId (string): The ID of the workflow to execute
  • input (any, optional): Input data to pass to the workflow
  • options (ExecutionOptions, optional):
    • timeout (number): Timeout in milliseconds (default: 30000)
    • stream (boolean): Enable streaming responses (default: false)
    • selectedOutputs (string[]): Block outputs to stream in blockName.attribute format (e.g., ["agent1.content"])
    • async (boolean): Execute asynchronously (default: false)

Returns: Promise<WorkflowExecutionResult | AsyncExecutionResult | PendingExecutionResult>

When async: true, returns HTTP 202 with a jobId, executionId, and statusUrl for polling. A synchronous request waits for completion, but may also return HTTP 202 with pending: true if its wait window expires. Poll that execution ID; another POST would start another run.

ModeInitial HTTP responseWhere the result appears
SyncThe executed root Response block's status and raw JSON data, or an execution envelopeThe SDK normalizes Response data into result.output
AsyncHTTP 202 admission receiptgetJobStatus(jobId).output when status === 'completed'
StreamHTTP 200 opens an SSE connectiononChunk receives selected outputs; the final message reports execution status and timing
Sync still runningHTTP 202 with pending: truegetJobStatus(executionId) retrieves the same run

A Response block's authored status applies to sync HTTP delivery. In async output it is represented as { data, status, headers }; job lookup still returns HTTP 200. Streaming also keeps HTTP 200 and reports the execution outcome in its terminal message. A child workflow's Response does not override the parent HTTP response.

executeWorkflowResponse()

Use this method to inspect the response kind, raw Response body, status, and headers without normalization:

const response = await client.executeWorkflowResponse<{ answer: number }>('workflow-id');
if (response.kind === 'response') {
  console.log(response.status, response.headers, response.body);
} else if (response.kind === 'async' || response.kind === 'pending') {
  console.log(response.body.executionId, response.body.statusUrl);
} else {
  console.log(response.body);
}

Kinds come from the server's X-SteelEngine-Response-Type header, so authored fields such as success, async, or output are never mistaken for transport control fields. Bodyless Response statuses (204/205) return null. Non-2xx responses, including authored Response errors, throw SteelEngineError with status and body; they do not by themselves prove an engine failure.

HTTP 503 with code: 'RESULT_UNAVAILABLE' means the run's exact result could not be recovered. STREAM_INCOMPLETE means selected delivery could not be verified. Use the error's executionId or statusUrl to retrieve the existing run. An SDK timeout, abort, or disconnected stream cancels the HTTP request only. API-key callers can poll with the same authorized key; the builder's reconnect endpoint requires a session.

getWorkflowStatus()

Get the status of a workflow (deployment status, etc.).

const status = await client.getWorkflowStatus('workflow-id');
console.log('Is deployed:', status.isDeployed);

Parameters:

  • workflowId (string): The ID of the workflow

Returns: Promise<WorkflowStatus>

validateWorkflow()

Validate that a workflow is ready for execution.

const isReady = await client.validateWorkflow('workflow-id');
if (isReady) {
  // Workflow is deployed and ready
}

Parameters:

  • workflowId (string): The ID of the workflow

Returns: Promise<boolean>

getJobStatus()

Get the status of an async job execution.

const status = await client.getJobStatus('job-id-from-async-execution');
console.log('Status:', status.status); // 'queued', 'processing', 'completed', 'failed'
if (status.status === 'completed') {
  console.log('Output:', status.output);
}

Parameters:

  • jobId (string): The job ID returned from async execution (AsyncExecutionResult.jobId)

Returns: Promise<JobStatus>

Response fields:

  • success (boolean): Whether the request was successful
  • jobId (string): The job ID
  • status (string): One of 'queued', 'processing', 'paused', 'completed', 'failed', 'cancelled'. Paused runs need input and are not complete.
  • metadata (object): Contains startedAt, completedAt, and duration
  • output (any, optional): The workflow output (when completed)
  • error (any, optional): Error details (when failed)
  • estimatedDuration (number, optional): Estimated duration in milliseconds (when processing/queued)
executeWithRetry()

Execute a workflow with automatic retry on rate limit errors using exponential backoff.

const result = await client.executeWithRetry('workflow-id', { message: 'Hello' }, {
  timeout: 30000
}, {
  maxRetries: 3,           // Maximum number of retries
  initialDelay: 1000,      // Initial delay in ms (1 second)
  maxDelay: 30000,         // Maximum delay in ms (30 seconds)
  backoffMultiplier: 2     // Exponential backoff multiplier
});

Parameters:

  • workflowId (string): The ID of the workflow to execute
  • input (any, optional): Input data to pass to the workflow
  • options (ExecutionOptions, optional): Same as executeWorkflow()
  • retryOptions (RetryOptions, optional):
    • maxRetries (number): Maximum number of retries (default: 3)
    • initialDelay (number): Initial delay in ms (default: 1000)
    • maxDelay (number): Maximum delay in ms (default: 30000)
    • backoffMultiplier (number): Backoff multiplier (default: 2)

Returns: Promise<WorkflowExecutionResult | AsyncExecutionResult>

The retry logic uses exponential backoff (1s → 2s → 4s → 8s...) with ±25% jitter to prevent thundering herd. If the API provides a retry-after header, it will be used instead.

getRateLimitInfo()

Get the current rate limit information from the last API response.

const rateLimitInfo = client.getRateLimitInfo();
if (rateLimitInfo) {
  console.log('Limit:', rateLimitInfo.limit);
  console.log('Remaining:', rateLimitInfo.remaining);
  console.log('Reset:', new Date(rateLimitInfo.reset * 1000));
}

Returns: RateLimitInfo | null

getUsageLimits()

Get current usage limits and quota information for your account.

const limits = await client.getUsageLimits();
console.log('Sync requests remaining:', limits.rateLimit.sync.remaining);
console.log('Async requests remaining:', limits.rateLimit.async.remaining);
console.log('Current period cost:', limits.usage.currentPeriodCost);
console.log('Plan:', limits.usage.plan);

Returns: Promise<UsageLimits>

Response structure:

{
  success: boolean
  rateLimit: {
    sync: {
      isLimited: boolean
      limit: number
      remaining: number
      resetAt: string
    }
    async: {
      isLimited: boolean
      limit: number
      remaining: number
      resetAt: string
    }
    authType: string  // 'api' or 'manual'
  }
  usage: {
    currentPeriodCost: number
    limit: number
    plan: string  // e.g., 'free', 'pro'
  }
}
setApiKey()

Update the API key.

client.setApiKey('new-api-key');
setBaseUrl()

Update the base URL.

client.setBaseUrl('https://my-custom-domain.com');

Types

WorkflowExecutionResult

interface WorkflowExecutionResult {
  success: boolean;
  output?: any;
  error?: string;
  logs?: any[];
  metadata?: {
    duration?: number;
    executionId?: string;
    [key: string]: any;
  };
  traceSpans?: any[];
  totalDuration?: number;
}

AsyncExecutionResult

interface AsyncExecutionResult {
  success: boolean;
  async: true;
  jobId: string;
  executionId: string;
  message: string;
  statusUrl: string;  // e.g., "https://steelengine.com/api/jobs/{jobId}"
}

WorkflowStatus

interface WorkflowStatus {
  isDeployed: boolean;
  deployedAt?: string;
  needsRedeployment: boolean;
}

RateLimitInfo

interface RateLimitInfo {
  limit: number;
  remaining: number;
  reset: number;
  retryAfter?: number;
}

UsageLimits

interface UsageLimits {
  success: boolean;
  rateLimit: {
    sync: {
      isLimited: boolean;
      limit: number;
      remaining: number;
      resetAt: string;
    };
    async: {
      isLimited: boolean;
      limit: number;
      remaining: number;
      resetAt: string;
    };
    authType: string;
  };
  usage: {
    currentPeriodCost: number;
    limit: number;
    plan: string;
  };
}

SteelEngineError

class SteelEngineError extends Error {
  code?: string;
  status?: number;
}

Common error codes:

  • UNAUTHORIZED: Invalid API key
  • TIMEOUT: Request timed out
  • RATE_LIMIT_EXCEEDED: Rate limit exceeded
  • USAGE_LIMIT_EXCEEDED: Usage limit exceeded
  • EXECUTION_ERROR: Workflow execution failed

Examples

Basic Workflow Execution

Set up the SteelEngineClient with your API key.

Check if the workflow is deployed and ready for execution.

Run the workflow with your input data.

Process the execution result and handle any errors.

import { SteelEngineClient } from '@steelengine/sdk';

const client = new SteelEngineClient({
  apiKey: process.env.STEELENGINE_API_KEY!
});

async function runWorkflow() {
  try {
    // Check if workflow is ready
    const isReady = await client.validateWorkflow('my-workflow-id');
    if (!isReady) {
      throw new Error('Workflow is not deployed or ready');
    }

    // Execute the workflow
    const result = await client.executeWorkflow('my-workflow-id', {
        message: 'Process this data',
        userId: '12345'
    });

    if (result.success) {
      console.log('Output:', result.output);
      console.log('Duration:', result.metadata?.duration);
    } else {
      console.error('Workflow failed:', result.error);
    }
  } catch (error) {
    console.error('Error:', error);
  }
}

runWorkflow();

Error Handling

Handle different types of errors that may occur during workflow execution:

import { SteelEngineClient, SteelEngineError } from '@steelengine/sdk';

const client = new SteelEngineClient({
  apiKey: process.env.STEELENGINE_API_KEY!
});

async function executeWithErrorHandling() {
  try {
    const result = await client.executeWorkflow('workflow-id');
    return result;
  } catch (error) {
    if (error instanceof SteelEngineError) {
      switch (error.code) {
        case 'UNAUTHORIZED':
          console.error('Invalid API key');
          break;
        case 'TIMEOUT':
          console.error('Workflow execution timed out');
          break;
        case 'USAGE_LIMIT_EXCEEDED':
          console.error('Usage limit exceeded');
          break;
        case 'INVALID_JSON':
          console.error('Invalid JSON in request body');
          break;
        default:
          console.error('Workflow error:', error.message);
      }
    } else {
      console.error('Unexpected error:', error);
    }
    throw error;
  }
}

Environment Configuration

Configure the client using environment variables:

import { SteelEngineClient } from '@steelengine/sdk';

// Development configuration
const apiKey = process.env.STEELENGINE_API_KEY;
if (!apiKey) {
  throw new Error('STEELENGINE_API_KEY environment variable is required');
}

const client = new SteelEngineClient({
  apiKey,
  baseUrl: process.env.STEELENGINE_BASE_URL // optional
});

Node.js Express Integration

Integrate with an Express.js server:

import express from 'express';
import { SteelEngineClient } from '@steelengine/sdk';

const app = express();
const client = new SteelEngineClient({
  apiKey: process.env.STEELENGINE_API_KEY!
});

app.use(express.json());

app.post('/execute-workflow', async (req, res) => {
  try {
    const { workflowId, input } = req.body;
    
    const result = await client.executeWorkflow(workflowId, input, {
      timeout: 60000
    });

    res.json({
      success: true,
      data: result
    });
  } catch (error) {
    console.error('Workflow execution error:', error);
    res.status(500).json({
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error'
    });
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Next.js API Route

Use with Next.js API routes:

// pages/api/workflow.ts or app/api/workflow/route.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { SteelEngineClient } from '@steelengine/sdk';

const client = new SteelEngineClient({
  apiKey: process.env.STEELENGINE_API_KEY!
});

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  try {
    const { workflowId, input } = req.body;

    const result = await client.executeWorkflow(workflowId, input, {
      timeout: 30000
    });

    res.status(200).json(result);
  } catch (error) {
    console.error('Error executing workflow:', error);
    res.status(500).json({
      error: 'Failed to execute workflow'
    });
  }
}

Browser Usage

Use in the browser (with proper CORS configuration):

import { SteelEngineClient } from '@steelengine/sdk';

// Note: In production, use a proxy server to avoid exposing API keys
const client = new SteelEngineClient({
  apiKey: 'your-public-api-key', // Use with caution in browser
  baseUrl: 'https://steelengine.com'
});

async function executeClientSideWorkflow() {
  try {
    const result = await client.executeWorkflow('workflow-id', {
        userInput: 'Hello from browser'
    });

    console.log('Workflow result:', result);

    // Update UI with result
    document.getElementById('result')!.textContent =
      JSON.stringify(result.output, null, 2);
  } catch (error) {
    console.error('Error:', error);
  }
}

File Upload

File objects are automatically detected and converted to base64 format. Include them in your input under the field name matching your workflow's API trigger input format.

The SDK converts File objects to this format:

{
  type: 'file',
  data: 'data:mime/type;base64,base64data',
  name: 'filename',
  mime: 'mime/type'
}

Alternatively, you can manually provide files using the URL format:

{
  type: 'url',
  data: 'https://example.com/file.pdf',
  name: 'file.pdf',
  mime: 'application/pdf'
}
import { SteelEngineClient } from '@steelengine/sdk';

const client = new SteelEngineClient({
  apiKey: process.env.NEXT_PUBLIC_STEELENGINE_API_KEY!
});

// From file input
async function handleFileUpload(event: Event) {
  const input = event.target as HTMLInputElement;
  const files = Array.from(input.files || []);

  // Include files under the field name from your API trigger's input format
  const result = await client.executeWorkflow('workflow-id', {
      documents: files,  // Must match your workflow's "files" field name
      instructions: 'Analyze these documents'
  });

  console.log('Result:', result);
}

When using the SDK in the browser, be careful not to expose sensitive API keys. Consider using a backend proxy or public API keys with limited permissions.

React Hook Example

Create a custom React hook for workflow execution:

import { useState, useCallback } from 'react';
import { SteelEngineClient, WorkflowExecutionResult } from '@steelengine/sdk';

const client = new SteelEngineClient({
  apiKey: process.env.STEELENGINE_API_KEY!
});

interface UseWorkflowResult {
  result: WorkflowExecutionResult | null;
  loading: boolean;
  error: Error | null;
  executeWorkflow: (workflowId: string, input?: any) => Promise<void>;
}

export function useWorkflow(): UseWorkflowResult {
  const [result, setResult] = useState<WorkflowExecutionResult | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  const executeWorkflow = useCallback(async (workflowId: string, input?: any) => {
    setLoading(true);
    setError(null);
    setResult(null);

    try {
      const workflowResult = await client.executeWorkflow(workflowId, input, {
        timeout: 30000
      });
      setResult(workflowResult);
    } catch (err) {
      setError(err instanceof Error ? err : new Error('Unknown error'));
    } finally {
      setLoading(false);
    }
  }, []);

  return {
    result,
    loading,
    error,
    executeWorkflow
  };
}

// Usage in component
function WorkflowComponent() {
  const { result, loading, error, executeWorkflow } = useWorkflow();

  const handleExecute = () => {
    executeWorkflow('my-workflow-id', {
      message: 'Hello from React!'
    });
  };

  return (
    <div>
      <button onClick={handleExecute} disabled={loading}>
        {loading ? 'Executing...' : 'Execute Workflow'}
      </button>

      {error && <div>Error: {error.message}</div>}
      {result && (
        <div>
          <h3>Result:</h3>
          <pre>{JSON.stringify(result, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}

Async Workflow Execution

Execute workflows asynchronously for long-running tasks:

import { SteelEngineClient, AsyncExecutionResult } from '@steelengine/sdk';

const client = new SteelEngineClient({
  apiKey: process.env.STEELENGINE_API_KEY!
});

async function executeAsync() {
  try {
    // Start async execution
    const result = await client.executeWorkflow('workflow-id', { data: 'large dataset' }, {
      async: true  // Execute asynchronously
    });

    // Check if result is an async execution
    if ('jobId' in result) {
      console.log('Job ID:', result.jobId);
      console.log('Status endpoint:', result.links.status);

      // Poll for completion
      let status = await client.getJobStatus(result.jobId);

      while (status.status === 'queued' || status.status === 'processing') {
        console.log('Current status:', status.status);
        await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds
        status = await client.getJobStatus(result.jobId);
      }

      if (status.status === 'completed') {
        console.log('Workflow completed!');
        console.log('Output:', status.output);
        console.log('Duration:', status.metadata.duration);
      } else {
        console.error('Workflow failed:', status.error);
      }
    }
  } catch (error) {
    console.error('Error:', error);
  }
}

executeAsync();

Rate Limiting and Retry

Handle rate limits automatically with exponential backoff:

import { SteelEngineClient, SteelEngineError } from '@steelengine/sdk';

const client = new SteelEngineClient({
  apiKey: process.env.STEELENGINE_API_KEY!
});

async function executeWithRetryHandling() {
  try {
    // Automatically retries on rate limit
    const result = await client.executeWithRetry('workflow-id', { message: 'Process this' }, {}, {
      maxRetries: 5,
      initialDelay: 1000,
      maxDelay: 60000,
      backoffMultiplier: 2
    });

    console.log('Success:', result);
  } catch (error) {
    if (error instanceof SteelEngineError && error.code === 'RATE_LIMIT_EXCEEDED') {
      console.error('Rate limit exceeded after all retries');

      // Check rate limit info
      const rateLimitInfo = client.getRateLimitInfo();
      if (rateLimitInfo) {
        console.log('Rate limit resets at:', new Date(rateLimitInfo.reset * 1000));
      }
    }
  }
}

Usage Monitoring

Monitor your account usage and limits:

import { SteelEngineClient } from '@steelengine/sdk';

const client = new SteelEngineClient({
  apiKey: process.env.STEELENGINE_API_KEY!
});

async function checkUsage() {
  try {
    const limits = await client.getUsageLimits();

    console.log('=== Rate Limits ===');
    console.log('Sync requests:');
    console.log('  Limit:', limits.rateLimit.sync.limit);
    console.log('  Remaining:', limits.rateLimit.sync.remaining);
    console.log('  Resets at:', limits.rateLimit.sync.resetAt);
    console.log('  Is limited:', limits.rateLimit.sync.isLimited);

    console.log('\nAsync requests:');
    console.log('  Limit:', limits.rateLimit.async.limit);
    console.log('  Remaining:', limits.rateLimit.async.remaining);
    console.log('  Resets at:', limits.rateLimit.async.resetAt);
    console.log('  Is limited:', limits.rateLimit.async.isLimited);

    console.log('\n=== Usage ===');
    console.log('Current period cost: $' + limits.usage.currentPeriodCost.toFixed(2));
    console.log('Limit: $' + limits.usage.limit.toFixed(2));
    console.log('Plan:', limits.usage.plan);

    const percentUsed = (limits.usage.currentPeriodCost / limits.usage.limit) * 100;
    console.log('Usage: ' + percentUsed.toFixed(1) + '%');

    if (percentUsed > 80) {
      console.warn('⚠️  Warning: You are approaching your usage limit!');
    }
  } catch (error) {
    console.error('Error checking usage:', error);
  }
}

checkUsage();

Streaming Workflow Execution

Execute workflows with real-time streaming responses:

import { SteelEngineClient } from '@steelengine/sdk';

const client = new SteelEngineClient({
  apiKey: process.env.STEELENGINE_API_KEY!
});

async function executeWithStreaming() {
  try {
    // Enable streaming for specific block outputs
    const result = await client.executeWorkflow('workflow-id', { message: 'Count to five' }, {
      stream: true,
      selectedOutputs: ['agent1.content'], // Use blockName.attribute format
      onChunk: ({ blockId, outputId, invocationId, chunk }) => {
        // Accumulate each field/invocation separately when selecting several outputs.
        process.stdout.write(chunk);
      }
    });

    console.log('Workflow result:', result);
  } catch (error) {
    console.error('Error:', error);
  }
}

The SDK requests stream version 2 with X-SteelEngine-Stream-Version: 2. Direct HTTP clients should send that header too; callers without it retain the legacy nested final message. The streaming response follows the Server-Sent Events (SSE) format:

data: {"blockId":"7b7735b9-19e5-4bd6-818b-46aae2596e9f","chunk":"One"}

data: {"blockId":"7b7735b9-19e5-4bd6-818b-46aae2596e9f","chunk":", two"}

data: {"event":"done","success":true,"output":{},"metadata":{"duration":610}}

data: [DONE]

Chunks also carry outputId and invocationId, distinguishing multiple fields and repeated blocks. A single selected content field can arrive as live text when its block supports it; other selected values arrive after their producing block settles. Strings are unchanged; other values are JSON-serialized. No separators are inserted. A successful selected stream ends with done.output: {} because the values were already delivered. Without selections, done.output contains the terminal workflow output.

The SDK resolves only after a terminal result and [DONE]. Received chunks or a closed connection alone are not success. A terminal status: 'paused' ends this stream segment while the run waits for input. Check success and status before treating the workflow as finished.

Timing values are milliseconds. When timingSemanticsVersion is 2, duration reflects active execution time, while waitDurationMs and elapsedDurationMs distinguish waiting from total wall time. Repeated polling retains the original completion timestamp and timing.

Using streaming in a web app:

Run the SDK on your backend and forward its onChunk messages through your application's authenticated streaming endpoint. In the UI, keep each selected field/invocation separate, show incoming chunks as progress, and clear the loading state only after the final result. Show a paused run as waiting for input, and a disconnected stream as incomplete with a link to check its execution status.

If you consume raw SSE instead, retain the decoder and an unfinished-frame buffer across network reads. A network read can end halfway through a UTF-8 character or a JSON message. Require the terminal result and [DONE]; do not ignore malformed JSON or treat transport closure as successful completion.

Getting Your API Key

Navigate to SteelEngine and log in to your account.

Navigate to the workflow you want to execute programmatically.

Click on "Deploy" to deploy your workflow if it hasn't been deployed yet.

During the deployment process, select or create an API key.

Copy the API key to use in your TypeScript/JavaScript application.

Requirements

  • Node.js 16+
  • TypeScript 5.0+ (for TypeScript projects)

Common Questions

Yes. Workflows must be deployed before they can be executed through the SDK. You can use the validateWorkflow() method to check whether a workflow is deployed and ready. If it returns false, deploy the workflow from the SteelEngine UI first and create or select an API key during deployment.
Sync execution waits for the result; if its wait window expires, it returns a pending receipt for the same execution. Async execution immediately returns a jobId and statusUrl. Poll with getJobStatus() using the same API key. Statuses include queued, processing, paused, completed, failed, and cancelled. Paused means the run needs input. Another execution request starts a new run.
Set stream: true and select fields using blockName.attribute (for example, ['agent1.content']). Chunks identify the block, selected field, and invocation. Supported text can arrive live; other values arrive after their block settles. The SDK waits for both the terminal result and [DONE]. Check success and status: receiving chunks or opening the HTTP connection does not mean the run completed.
The SDK provides built-in rate limiting support through the executeWithRetry() method. It uses exponential backoff (1s, 2s, 4s, 8s...) with 25% jitter to avoid thundering herd problems. If the API returns a retry-after header, that value is used instead. You can configure maxRetries, initialDelay, maxDelay, and backoffMultiplier. Use getRateLimitInfo() to check your current rate limit status.
You can use the SDK in the browser, but you should not expose your API key in client-side code. In production, use a backend proxy server to handle SDK calls, or use a public API key with limited permissions. The SDK works with both Node.js and browser environments, but sensitive keys should stay server-side.
File objects are automatically detected and converted to base64 format. Include them in the input object under the field name that matches your workflow's API trigger input format. In the browser, pass File objects directly from file inputs. In Node.js, create File objects from buffers. You can also provide files as URL references with type, data, name, and mime fields.

On this page