Skip to main content
This guide provides practical examples for integrating Simplex into your TypeScript applications.

Installation

npm install simplex-ts

Initializing the client

import Simplex from 'simplex-ts';

const client = new Simplex({
  apiKey: process.env.SIMPLEX_API_KEY
});

Configuration options

const client = new Simplex({
  apiKey: process.env.SIMPLEX_API_KEY,
  timeout: 30000,      // Request timeout in ms (default: 30000)
  maxRetries: 3,       // Number of retry attempts (default: 3)
  retryDelay: 1000     // Delay between retries in ms (default: 1000)
});

Running workflows

Basic workflow execution

const result = await client.workflows.run('workflow_id', {
  variables: {
    username: '[email protected]',
    search_query: 'order #12345'
  }
});

console.log('Session ID:', result.session_id);

With debug webhook callback (useful for local testing)

const result = await client.workflows.run('workflow_id', {
  variables: {
    patient_id: 'P-12345'
  },
  webhook_url: 'https://59d9f4dbc.ngrok-free.app/api/webhook',
  metadata: {
    internal_id: 'req-789',
    source: 'api'
  }
});

Handling webhook responses

Next.js App Router

// app/api/simplex-webhook/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { verifySimplexWebhook, WebhookPayload } from 'simplex-ts';

export async function POST(request: NextRequest) {
  const body = await request.text();
  const headers: Record<string, string> = {};
  request.headers.forEach((value, key) => {
    headers[key] = value;
  });

  try {
    verifySimplexWebhook(body, headers, process.env.SIMPLEX_WEBHOOK_SECRET!);
    const payload: WebhookPayload = JSON.parse(body);

    if (payload.success) {
      // Process successful workflow
      await processResult(payload);
    } else {
      // Handle failed workflow
      await handleFailure(payload);
    }

    return NextResponse.json({ received: true });
  } catch (error) {
    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
  }
}

async function processResult(payload: WebhookPayload) {
  const { session_id, structured_output, metadata } = payload;

  // Your business logic here
  console.log('Processing session:', session_id);

  if (structured_output) {
    // Handle extracted data
    await saveToDatabase(structured_output);
  }
}

async function handleFailure(payload: WebhookPayload) {
  console.error('Workflow failed:', payload.session_id);
  // Alert, retry, or log the failure
}

Express

import express from 'express';
import { verifySimplexWebhook, WebhookPayload } from 'simplex-ts';

const app = express();

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const body = req.body.toString('utf8');
  const signature = req.headers['x-simplex-signature'] as string;

  try {
    verifySimplexWebhook(body, req.headers, process.env.SIMPLEX_WEBHOOK_SECRET!);
    const payload: WebhookPayload = JSON.parse(body);

    // Process asynchronously
    processWebhook(payload).catch(console.error);

    res.json({ received: true });
  } catch (error) {
    res.status(401).json({ error: 'Invalid signature' });
  }
});

app.listen(3000);

Retrieving session data

Get session replay

const replay = await client.retrieveSessionReplay('session_id');

// Returns MP4 video recording of the session
console.log('Replay URL:', replay.url);

Get session logs

const logs = await client.retrieveSessionLogs('session_id');

// Returns JSON session logs
for (const entry of logs.entries) {
  console.log(`[${entry.timestamp}] ${entry.level}: ${entry.message}`);
}

Get session store

const store = await client.getSessionStore('session_id');

// Access metadata about files downloaded during the session
console.log('Stored data:', store.data);

Download session files

// Download all files as a zip
const allFiles = await client.downloadSessionFiles('session_id');

// Or download a specific file
const specificFile = await client.downloadSessionFiles('session_id', 'report.pdf');

Batch processing

Running multiple workflows

const patients = ['P-001', 'P-002', 'P-003', 'P-004', 'P-005'];

// Run workflows in parallel with concurrency limit
const results = await Promise.all(
  patients.map(async (patientId) => {
    try {
      return await client.workflows.run('verification_workflow', {
        variables: { patient_id: patientId },
        webhook_url: 'https://your-domain.com/webhook',
        metadata: { patient_id: patientId }
      });
    } catch (error) {
      console.error(`Failed to start workflow for ${patientId}:`, error);
      return null;
    }
  })
);

const successful = results.filter(Boolean);
console.log(`Started ${successful.length}/${patients.length} workflows`);

With rate limiting

async function runWithRateLimit<T>(
  items: T[],
  fn: (item: T) => Promise<unknown>,
  concurrency: number = 5,
  delayMs: number = 1000
) {
  const results = [];

  for (let i = 0; i < items.length; i += concurrency) {
    const batch = items.slice(i, i + concurrency);
    const batchResults = await Promise.all(batch.map(fn));
    results.push(...batchResults);

    if (i + concurrency < items.length) {
      await new Promise(resolve => setTimeout(resolve, delayMs));
    }
  }

  return results;
}

// Usage
await runWithRateLimit(
  patients,
  (patientId) => client.workflows.run('workflow_id', {
    variables: { patient_id: patientId }
  }),
  5,  // 5 concurrent
  1000 // 1 second between batches
);

Searching workflows

// Search for workflows by name or metadata
const results = await client.workflows.search({
  name: 'insurance'  // Partial matching supported
});

for (const workflow of results) {
  console.log(`${workflow.name}: ${workflow.id}`);
}

Updating workflow metadata

await client.workflows.updateMetadata('workflow_id', {
  category: 'verification',
  priority: 'high'
});

Creating workflow sessions

// Create a new workflow session with a starting URL
const session = await client.workflows.createWorkflowSession(
  'My Session',
  'https://example.com/portal',
  {
    variables: { username: '[email protected]' }
  }
);

// Run agentic tasks within the session
await client.workflows.agentic(
  'Click the login button and enter credentials',
  session.id,
  { timeout: 30000 }
);

// Or run a pre-configured agent
await client.workflows.run_agent('login_agent', session.id, {
  username: '[email protected]',
  password: 'secure_password'
});

Error handling

import Simplex, {
  WorkflowError,
  ValidationError,
  AuthenticationError,
  RateLimitError,
  NetworkError
} from 'simplex-ts';

async function runWorkflowSafely(workflowId: string, variables: Record<string, string>) {
  try {
    return await client.workflows.run(workflowId, { variables });
  } catch (error) {
    if (error instanceof AuthenticationError) {
      console.error('Invalid API key');
      throw error;
    }

    if (error instanceof RateLimitError) {
      console.log('Rate limited, retrying after delay...');
      await new Promise(resolve => setTimeout(resolve, 5000));
      return client.workflows.run(workflowId, { variables });
    }

    if (error instanceof ValidationError) {
      console.error('Invalid parameters:', error.message);
      throw error;
    }

    if (error instanceof WorkflowError) {
      console.error('Workflow execution failed:', error.message);
      throw error;
    }

    if (error instanceof NetworkError) {
      console.error('Network issue:', error.message);
      throw error;
    }

    throw error;
  }
}

TypeScript types

The SDK exports types for all API responses:
import type {
  WebhookPayload,
  WorkflowRunResponse,
  SessionReplay,
  SessionLogs,
  SessionStore,
  FileMetadata
} from 'simplex-ts';

function handleWebhook(payload: WebhookPayload) {
  const {
    success,
    session_id,
    agent_response,
    structured_output,
    metadata,
    file_metadata
  } = payload;

  // TypeScript knows all the types
}

Environment configuration

// config.ts
export const simplexConfig = {
  apiKey: process.env.SIMPLEX_API_KEY!,
  webhookSecret: process.env.SIMPLEX_WEBHOOK_SECRET!,
  webhookUrl: process.env.NODE_ENV === 'production'
    ? 'https://your-domain.com/api/webhook'
    : process.env.NGROK_URL + '/api/webhook'
};

// Validate config on startup
if (!simplexConfig.apiKey) {
  throw new Error('SIMPLEX_API_KEY is required');
}

Next steps