Skip to main content
This guide provides practical examples for integrating Simplex into your applications using the TypeScript or Python SDK.

Installation

npm install simplex-ts

Initializing the client

import { SimplexClient } from 'simplex-ts';

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

Configuration options

const client = new SimplexClient({
  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: 'user@example.com',
    search_query: 'order #12345'
  }
});

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

With webhook callback

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

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) {
      await processResult(payload);
    } else {
      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;
  console.log('Processing session:', session_id);

  if (structured_output) {
    await saveToDatabase(structured_output);
  }
}

async function handleFailure(payload: WebhookPayload) {
  console.error('Workflow failed:', payload.session_id);
}

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');

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

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

app.listen(3000);

Polling session status

const status = await client.getSessionStatus('session_id');

if (status.paused) {
  console.log('Session paused, pause key:', status.paused_key);
  await client.resume('session_id');
} else if (status.in_progress) {
  console.log('Session still running...');
} else if (status.success) {
  console.log('Session completed successfully');
  console.log('Files:', status.file_metadata);
  console.log('Scraper outputs:', status.scraper_outputs);
} else {
  console.log('Session failed');
}

Resuming paused flows

When a flow script calls pause(), you can resume it programmatically:
const result = await client.resume('session_id');

if (result.succeeded) {
  console.log('Flow resumed successfully');
} else {
  console.log('Failed to resume:', result.error);
}

Streaming live events

Live event streaming is not yet available in the TypeScript SDK. Use webhooks or polling instead.

Retrieving session data

Get session replay

import fs from 'fs';

const replay = await client.retrieveSessionReplay('session_id');
fs.writeFileSync('session-replay.mp4', Buffer.from(replay));

Get session logs

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

if (logs === null) {
  console.log('Session is still running, logs not yet available');
} else {
  console.log('Session logs:', JSON.stringify(logs, null, 2));
}

Download session files

const allFiles = await client.downloadSessionFiles('session_id');

Batch processing

Running multiple workflows

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

const results = await Promise.all(
  patients.map(async (patientId) => {
    try {
      return await client.workflows.run('verification_workflow', {
        variables: { patient_id: patientId },
        webhookUrl: 'https://your-domain.com/webhook',
        metadata: 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;
}

await runWithRateLimit(
  patients,
  (patientId) => client.workflows.run('workflow_id', {
    variables: { patient_id: patientId }
  }),
  5,
  1000
);

Searching workflows

const results = await client.workflows.search({
  workflowName: 'insurance'
});

for (const workflow of results.workflows) {
  console.log(`${workflow.workflow_name}: ${workflow.workflow_id}`);
}

Error handling

import { SimplexClient,
  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;
  }
}

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

if (!simplexConfig.apiKey) {
  throw new Error('SIMPLEX_API_KEY is required');
}

Next steps