Workflow API

SEON's Workflow API enables you to initialize and manage verification workflows that combine document verification, selfie checks, fraud detection, and AML screening in a single orchestrated flow. Use this endpoint to start a workflow session and receive a token for the frontend SDK.

Good to know

  • The workflowId must be a valid UUID of an active workflow created in the Admin Panel (Admin Panel / Workflows).
  • The user_id field is always required in the inputs object to identify the end user.
  • Additional required inputs depend on your workflow configuration (e.g., email if Email check is enabled, phone_number if Phone check is enabled).
  • All SEON API requests are case-sensitive. Please follow the formatting below to avoid errors.
  • IP address is auto-captured from the end user's browser if not provided in the request.
  • Device fingerprinting is handled automatically by the SDK when Device check is enabled.
  • All Fraud API input fields are accepted. The Workflow API supports the complete set of fields from the Fraud API, plus additional orchestration-specific fields (e.g., reference_image, eKYC identifiers). See the Fraud API documentation for the full list of available fields.

For more context on how to begin your API integration check the Introduction section or our Integration Guide.

 

Common Workflow Scenarios

Workflow TypeRequired Inputs
Document + Selfie (basic)user_id 
Document + Selfie + Face Match (URL)user_id, reference_image
Email + Phone fraud checkuser_id, email, phone_number
Full fraud check (Email + Phone + IP)user_id, email, phone_number, (IP auto-captured)
AML screeninguser_id, user_fullname
NIN eKYC (Nigeria)user_id, user_firstname, user_lastname, user_dob, nin
BVN eKYC (Nigeria)user_id, user_firstname, user_lastname, user_dob, nin
CPF eKYC (Brazil)user_id, cpf

Request

 

Request Attributes

TypeRequired
workflowId
string (UUID)yes
inputs
objectyes

HTTP Endpoint

POST

https://api.seon.io/orchestration-api/v1/init-workflow
PHP
Generic
Generic

Response

The endpoint returns JSON structured response.

JSON Attributes

 Type
executionId
 string (UUID)
token
 string
Response
{
 "data": {
  "executionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
 }
}

Error Responses

 

HTTP StatusError CodeDescription
400MISSING_REQUIRED_INPUTSRequired workflow inputs not provided (e.g., missing user_id or workflow-specific fields).
401INVALID_INPUT_FORMATInput field format is incorrect (e.g., invalid email format).
402UNAUTHORIZEDInvalid or missing API key.
403FORBIDDENAPI key doesn't have access to this workflow.
404WORKFLOW_NOT_FOUNDWorkflow ID doesn't exist or workflow is inactive.
429RATE_LIMITEDToo many requests. Implement exponential backoff.
500INTERNAL_ERRORInternal server error. Contact SEON support with your executionId.

 

Orchestration SDK

You can integrate SEON's Orchestration module directly into a web app by using our JavaScript SDK. Please use our npm-hosted package to ensure you always load the latest available version.

Visit the SEON Orchestration SDK npm page to see the latest version and its changelog.

  1. Install the SDK via npm or yarn and import it into your application.
  2. Initialize a workflow from your backend using the Workflow API described above to get a token.
  3. Call SeonOrchestration.start(config) with the token to launch the verification flow.
  4. Listen to events (completed, error, cancelled) to handle the verification result.
  5. Use webhooks or the Admin Panel to access detailed verification results and captured media.

Installation

npm / yarn

npm install @seontechnologies/seon-orchestration
# or
yarn add @seontechnologies/seon-orchestration

Import

import { SeonOrchestration } from '@seontechnologies/seon-orchestration';

 

Prerequisites

  • Node.js >=20.0.0, npm >=7.0.0
  • SEON account with workflow access
  • API key (obtain from Admin Panel / Settings / API Keys)
  • At least one workflow created (Admin Panel / Workflows)

 

Browser Compatibility

BrowserMin Version
Chrome96
Safari15
Firefox79
Opera82
iOS Safari 15
Android Browser81
Chrome for Android96
Firefox for Android79
Internet ExplorerNot Supported

 

Configuration parameters

To configure the Orchestration SDK, you need to create a config object and pass it to SeonOrchestration.start(config).

JSON Attributes

TypeRequired
token
stringyes
language
stringno
theme
objectno
renderingMode
stringno
containerId
stringconditional

 

Core Methods

MethodDescription
SeonOrchestration.start(config)Start verification flow with the provided configuration
SeonOrchestration.close()Close the current verification flow and clean up UI
SeonOrchestration.on(event, handler)Subscribe to SDK events
SeonOrchestration.off(event, handler)Unsubscribe from SDK events

 

Events

EventCallback SignatureDescription
opened() => voidFlow UI opened
closed() => voidFlow UI closed
started() => voidVerification started
completed(status: CompletionTypes) => voidVerification completed
cancelled() => voidUser cancelled
error(errorCode: ErrorCodes) => voidError occurred

Completion Types: success, pending, failed, unknown
 

Error Codes

Error codes received via the error event:

CodeDescription
error_code_1Device not supported — No capable camera/device found, or general error screen dismissed
error_code_3Authentication failed — Unauthorized request (invalid/expired token)
error_code_4Document capture SDK error — Failed to initialize document scanning
error_code_5Document capture retry limit exceeded — User exceeded max retries for document scanning
error_code_6Liveness check retry limit exceeded — User exceeded max retries for liveness detection
unknownUnhandled error — Unexpected error or unhandled promise rejection

 

SDK Exceptions

Exceptions thrown by SeonOrchestration.start() (catch via try/catch):

Error MessageCause
"IDV flow is already running."Calling start() when a flow is already active
"Configuration is not set."Calling start() without passing config
"Failed to initialize client: {status} {statusText}"Backend init failed (e.g., invalid/expired token)
"Invalid response from client init."Invalid account configuration
"Container ID is required for inline rendering."Using renderingMode: inline without containerId
"Container element with id '{id}' not found."Container DOM element doesn't exist
"Failed to open popup window. Please allow popups and try again."Browser blocked popup window
"Invalid rendering mode specified."Invalid renderingMode value

 

Example: Minimal Integration

javascript
import { SeonOrchestration } from '@seontechnologies/seon-orchestration';
// 1. Get token from YOUR backend (keeps API keys secure)
const { token } = await fetch('/api/init-verification', { method: 'POST' })
 .then(r => r.json());
// 2. Start verification
await SeonOrchestration.start({ token, language: 'en' });

 

Example: Full Configuration

// On page load: Set up event listeners
SeonOrchestration.on('completed', (status) => {
 console.log('Verification completed:', status);
});
SeonOrchestration.on('error', (errorCode) => {
 console.error('Verification error:', errorCode);
});
const config = {
 token: 'eyJhbGciOiJIUzI1NiIs...',  // From your backend
 language: 'en',
 renderingMode: 'fullscreen',
 theme: {
   light: {
     baseTextOnLight: '#1a1a1a',
     baseTextOnDark: '#ffffff',
     baseAccent: '#0066cc',
     baseOnAccent: '#ffffff',
     logoUrl: 'https://example.com/logo-dark.svg'
   },
   dark: {
     baseTextOnLight: '#e5e5e5',
     baseTextOnDark: '#1a1a1a',
     baseAccent: '#4d9fff',
     baseOnAccent: '#000000',
     logoUrl: 'https://example.com/logo-light.svg'
   },
   fontFamily: 'Inter',
   fontUrl: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap',
   fontWeight: '500'
 }
};
await SeonOrchestration.start(config);

 

Example: Inline Rendering

<!-- In your HTML -->
<div id="verification-container" style="width: 100%; min-height: 600px;"></div>

 

await SeonOrchestration.start({
 token,
 renderingMode: 'inline',
 containerId: 'verification-container'
});

 

RequirementDetails
Container elementMust exist in DOM before start() is called
Minimum size400×600 px recommended for usability
ResponsiveContainer should be responsive; SDK adapts to available space

 

 

Example: React Integration

import React, { useEffect, useState } from 'react';
import { SeonOrchestration, CompletionTypes, ErrorCodes } from '@seontechnologies/seon-orchestration';
export function VerificationComponent({ userId, onComplete, onError }) {
 const [isLoading, setIsLoading] = useState(false);
 const [error, setError] = useState(null);
 useEffect(() => {
   const handleCompleted = (status: CompletionTypes) => {
     onComplete(status);
   };
   const handleError = (errorCode: ErrorCodes) => {
     setError(`Error: ${errorCode}`);
     onError(errorCode);
   };
   const handleClosed = () => setIsLoading(false);
   SeonOrchestration.on('completed', handleCompleted);
   SeonOrchestration.on('error', handleError);
   SeonOrchestration.on('closed', handleClosed);
   return () => {
     SeonOrchestration.off('completed', handleCompleted);
     SeonOrchestration.off('error', handleError);
     SeonOrchestration.off('closed', handleClosed);
   };
 }, [onComplete, onError]);
 const startVerification = async () => {
   setIsLoading(true);
   setError(null);
   try {
     const response = await fetch('/api/init-verification', {
       method: 'POST',
       headers: { 'Content-Type': 'application/json' },
       body: JSON.stringify({ userId }),
     });
     const { token } = await response.json();
     await SeonOrchestration.start({ token, language: 'en' });
   } catch (err) {
     setError(err.message);
   } finally {
     setIsLoading(false);
   }
 };
 return (
   <div>
     {error && <div style={{ color: 'red' }}>{error}</div>}
     <button onClick={startVerification} disabled={isLoading}>
       {isLoading ? 'Starting...' : 'Start Verification'}
     </button>
   </div>
 );
}