Overview
This comprehensive guide covers everything you need to integrate with Hamsa’s platform, including REST APIs, real-time WebSocket connections, the Voice Agents SDK, webhooks, and the tool system. Whether you’re building a simple integration or a complex production system, this guide has you covered.
What This Guide Covers:
Authentication methods for all API types
REST API integration patterns
Real-time Speech-to-Text and Text-to-Speech APIs
Voice Agents Web SDK
Webhook integration for event-driven architectures
Tool system for extending agent capabilities
Error handling and edge cases
Rate limiting and quota management
Production best practices
Authentication
Hamsa uses different authentication methods depending on the API type. Understanding these is crucial for successful integration.
API Key Token Authentication
Used for all REST API endpoints.
# Header format
Authorization: Token < YOUR_API_KE Y >
# Example request
curl -X GET https://api.tryhamsa.com/v1/voice-agents \
-H "Authorization: Token sk_live_abc123xyz789" \
-H "Content-Type: application/json"
Security Best Practices:
Never expose API keys in client-side code
Store keys in environment variables or secure vaults
Use separate keys for development and production
Rotate keys periodically
Use least-privilege keys when possible
Bearer Token (JWT) Authentication
Used for webhooks and tool authentication that the user adds to the system.
# Header format
Authorization: Bearer < JWT_TOKE N >
# Example
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
For tools and integrations that require custom authentication schemes.
{
"headers" : [
{
"name" : "X-API-Key" ,
"value" : "your_custom_api_key"
},
{
"name" : "X-Client-ID" ,
"value" : "client_123"
}
]
}
Getting Your API Key
Navigate to API Keys
Go to Settings → API Keys in the dashboard
Create New Key
Click Create API Key and provide a descriptive name
Copy and Store Securely
Copy the key immediately - it won’t be shown again
REST API Integration
Base URL
All REST API requests use the following base URL:
API Versioning
Hamsa provides multiple API versions. Use the version specified in the endpoint path:
/v1/voice-agents # Version 1
/v2/voice-agents # Version 2 (recommended for new integrations)
Some v1 endpoints are marked as deprecated in the API reference. For these endpoints, migrate to the v2 equivalent when available. Endpoints not marked as deprecated are fully supported.
All requests should include:
Content-Type: application/json
Authorization: Token < YOUR_API_KE Y >
Almost all responses follow a consistent structure:
Success Response:
{
"success" : true ,
"data" : {
// Response data
}
}
Error Response:
{
"success" : false ,
"error" : {
"code" : "ERROR_CODE" ,
"message" : "Human-readable error message" ,
"details" : {}
}
}
Core API Endpoints
Voice Agents
Method Endpoint Description POST/v2/voice-agentsCreate a new voice agent GET/v2/voice-agentsList all voice agents GET/v2/voice-agents/{id}Get agent details PATCH/v2/voice-agents/{id}Update an agent POST/v1/voice-agents/cloneClone an existing agent POST/v1/voice-agents/callInitiate a call with an agent
Create Agent Example:
const response = await fetch ( 'https://api.tryhamsa.com/v2/voice-agents' , {
method: 'POST' ,
headers: {
'Authorization' : 'Token sk_live_abc123' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
name: 'Customer Support Agent' ,
preamble: 'You are a helpful customer support agent...' ,
greeting: 'Hello! How can I help you today?' ,
language: 'en-US' ,
voiceId: 'voice_abc123'
})
});
const data = await response . json ();
console . log ( 'Created agent:' , data . data . id );
Phone Numbers
Method Endpoint Description GET/v1/voice-agents/phone-numberList phone numbers POST/v1/voice-agents/phone-numberAdd a phone number DELETE/v1/voice-agents/phone-numberDelete a phone number POST/v1/voice-agents/assign-numberAssign number to agent POST/v1/voice-agents/unassignUnassign number from agent POST/v1/voice-agents/phone-number/callMake outbound call
Knowledge Base
Method Endpoint Description POST/v1/voice-agents/knowledge-baseCreate knowledge item GET/v1/voice-agents/knowledge-base/listList all items GET/v1/voice-agents/knowledge-base/{id}Get item details PATCH/v1/voice-agents/knowledge-base/{id}Update item DELETE/v1/voice-agents/knowledge-base/{id}Delete item POST/v1/voice-agents/knowledge-base/{id}/urlAdd URL to item POST/v1/voice-agents/knowledge-base/toggle-activationActivate/deactivate item
Knowledge Base Item Types:
TEXT - Structured text content (50-5,000 characters)
FILE - PDF, DOCS, DOC, TXT, HTML, EPUB.
URL - Web pages (up to 100 URLs per item)
Method Endpoint Description POST/v2/web-toolCreate a web tool GET/v2/web-tool/listList all tools PATCH/v2/web-tool/{id}Update a tool POST/v1/voice-agents/web-tool/test-api-toolTest a tool POST/v1/voice-agents/web-tool/toggle-activationActivate/deactivate
Campaigns (Outbound Calling)
Method Endpoint Description POST/v1/voice-agents/campaignsCreate campaign GET/v1/voice-agents/campaignsList campaigns GET/v1/voice-agents/campaigns/{id}Get campaign details PATCH/v1/voice-agents/campaigns/{id}Update campaign POST/v1/voice-agents/campaigns/{id}/pausePause campaign POST/v1/voice-agents/campaigns/{id}/resumeResume campaign POST/v1/voice-agents/campaigns/{id}/cancelCancel campaign POST/v1/voice-agents/campaigns/{id}/retryRetry failed calls
Call History & Conversations
Method Endpoint Description POST/v1/voice-agents/conversations/listList calls with filters GET/v1/voice-agents/conversation/{id}Get call details POST/v1/voice-agents/join-callJoin active call as listener
Method Endpoint Description POST/v1/jobs/transcribeTranscribe audio/video POST/v1/jobs/text-to-speechGenerate speech from text POST/v1/jobs/ai-contentGenerate AI Docs GET/v1/jobsGet job status POST/v1/jobs/allList all jobs
Real-Time APIs
Real-Time Speech-to-Text (WebSocket)
Connect to the real-time STT endpoint for live transcription:
const ws = new WebSocket ( 'wss://api.tryhamsa.com/v1/realtime/ws?api_key=YOUR_API_KEY' );
ws . onopen = async () => {
// Get audio from microphone
const stream = await navigator . mediaDevices . getUserMedia ({ audio: true });
const mediaRecorder = new MediaRecorder ( stream );
const chunks = [];
mediaRecorder . ondataavailable = ( e ) => chunks . push ( e . data );
mediaRecorder . onstop = async () => {
const blob = new Blob ( chunks );
const buffer = await blob . arrayBuffer ();
const base64 = btoa ( String . fromCharCode ( ... new Uint8Array ( buffer )));
ws . send ( JSON . stringify ({
type: 'stt' ,
payload: {
audioBase64: base64 ,
language: 'ar' ,
isEosEnabled: true ,
eosThreshold: 0.3
}
}));
};
mediaRecorder . start ();
setTimeout (() => mediaRecorder . stop (), 3000 ); // Record 3 seconds
};
ws . onmessage = ( event ) => {
if ( typeof event . data === 'string' ) {
try {
const json = JSON . parse ( event . data );
if ( json . type === 'error' ) {
console . error ( 'Error:' , json . payload . message );
}
} catch {
// Plain text transcription result
console . log ( 'Transcription:' , event . data );
}
}
};
Supported Audio Formats:
linear16 - 16-bit linear PCM
mulaw - 8-bit μ-law
Real-Time Text-to-Speech (REST)
Standard TTS Request:
const response = await fetch ( 'https://api.tryhamsa.com/v1/realtime/tts' , {
method: 'POST' ,
headers: {
'Authorization' : 'Token sk_live_abc123' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
text: 'Hello, how can I help you today?' ,
voiceId: 'voice_abc123' ,
speed: 1.0 ,
pitch: 1.0
})
});
const audioBlob = await response . blob ();
const audioUrl = URL . createObjectURL ( audioBlob );
Streaming TTS Request:
If you are facing any issues while working with this endpoint, please refer to this JSFiddle which has a solution our team created as an example.
const response = await fetch ( 'https://api.tryhamsa.com/v1/realtime/tts-stream' , {
method: 'POST' ,
headers: {
'Authorization' : 'Token sk_live_abc123' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
text: 'This is a longer text that will be streamed...' ,
voiceId: 'voice_abc123'
})
});
// Process streaming response
const reader = response . body . getReader ();
while ( true ) {
const { done , value } = await reader . read ();
if ( done ) break ;
// Process audio chunk
playAudioChunk ( value );
}
Voice Agents SDK Integration
The Hamsa Voice Agents SDK provides a seamless way to embed voice interactions into web applications.
Installation
npm install @hamsa-ai/voice-agents-sdk
Or via CDN:
< script src = "https://unpkg.com/@hamsa-ai/voice-agents-sdk@latest/dist/index.umd.js" ></ script >
Basic Usage
import { HamsaVoiceAgent } from '@hamsa-ai/voice-agents-sdk' ;
// Initialize
const agent = new HamsaVoiceAgent ( 'YOUR_API_KEY' );
// Start conversation
await agent . start ({
agentId: 'agent_abc123' ,
params: {
user_name: 'John Doe' ,
user_id: 'user_123' ,
session_id: 'session_abc'
},
voiceEnablement: true ,
userId: 'user_123'
});
// Event listeners
agent . on ( 'callStarted' , ({ jobId }) => {
console . log ( 'Call started:' , jobId );
});
agent . on ( 'transcriptionReceived' , ( text ) => {
console . log ( 'User said:' , text );
});
agent . on ( 'answerReceived' , ( text ) => {
console . log ( 'Agent said:' , text );
});
agent . on ( 'agentStateChanged' , ( state ) => {
// state: 'idle' | 'initializing' | 'listening' | 'thinking' | 'speaking'
updateUI ( state );
});
agent . on ( 'callEnded' , () => {
console . log ( 'Call ended' );
});
agent . on ( 'error' , ( error ) => {
console . error ( 'Error:' , error );
});
Advanced Configuration
await agent . start ({
agentId: 'agent_abc123' ,
voiceEnablement: true ,
// Custom parameters (echoed in webhooks)
params: {
application_id: '12345' ,
user_id: 'user_789' ,
session_id: 'sess_abc' ,
custom_data: JSON . stringify ({ key: 'value' })
},
// User tracking
userId: 'user_789' ,
// iOS optimization
preferHeadphonesForIosDevices: true ,
// Platform-specific connection delays
connectionDelay: {
android: 3000 , // Android needs longer delay
ios: 500 ,
default: 1000
},
// Audio capture for third-party services
onAudioData : ( audioData ) => {
thirdPartyWebSocket . send ( audioData );
},
// Client-side tools
tools: [
{
function_name: 'getUserInfo' ,
description: 'Get user information' ,
parameters: [
{ name: 'userId' , type: 'string' , description: 'User ID' }
],
required: [ 'userId' ],
fn : async ( userId ) => {
return await fetchUserInfo ( userId );
}
}
]
});
Audio Controls
// Volume control
agent . setVolume ( 0.8 );
const volume = agent . getOutputVolume ();
// Microphone control
agent . setMicMuted ( true );
agent . setMicMuted ( false );
const isMuted = agent . isMicMuted ();
// Audio levels
const inputLevel = agent . getInputVolume ();
const outputLevel = agent . getOutputVolume ();
// Frequency data for visualization
const inputFreqData = agent . getInputByteFrequencyData ();
const outputFreqData = agent . getOutputByteFrequencyData ();
Analytics & Monitoring
// Get comprehensive analytics
const analytics = agent . getCallAnalytics ();
console . log ( analytics );
/*
{
connectionStats: { quality: 'good', connectionAttempts: 1, ... },
audioMetrics: { userAudioLevel: 0.8, agentAudioLevel: 0.3, ... },
performanceMetrics: { callDuration: 60000, responseTime: 1200, ... },
participants: [...],
trackStats: { totalTracks: 2, activeTracks: 2, ... }
}
*/
// Real-time connection quality
agent . on ( 'connectionQualityChanged' , ({ quality , metrics }) => {
if ( quality === 'poor' ) {
showNetworkWarning ();
}
});
// Custom events from agent
agent . on ( 'customEvent' , ( eventType , eventData , metadata ) => {
if ( eventType === 'tool_execution' ) {
console . log ( 'Tool called:' , eventData . toolName );
}
});
Conversation Control
// Pause conversation
agent . pause ();
// Resume conversation
agent . resume ();
// End conversation
agent . end ();
// Get current job ID
const jobId = agent . getJobId ();
Webhook Integration
Webhooks provide real-time notifications about call events, transcriptions, and outcomes.
Webhook Events
Event Description When Triggered call.startedCall begins Call initiated call.answeredCall connected User picks up transcription.updateReal-time speech User/agent speaks tool.executedTool called Agent uses tool call.endedCall completes Call terminates
Setting Up Webhooks
Create Webhook Endpoint
Create a publicly accessible HTTPS endpoint that accepts POST requests.
Configure in Dashboard
Navigate to your agent’s settings and add the webhook URL.
Set Authentication
Configure Bearer token authentication for security.
Handle Events
Implement handlers for different event types.
Webhook Configuration
{
"webhookUrl" : "https://api.yourcompany.com/webhook/hamsa" ,
"webhookAuth" : {
"authKey" : "bearer" ,
"authSecret" : "Bearer your_secret_token_here"
}
}
Webhook Handler Implementation
const express = require ( 'express' );
const app = express ();
app . use ( express . json ());
// Verify Bearer token
function verifyToken ( req , res , next ) {
const authHeader = req . headers . authorization ;
const expectedToken = process . env . WEBHOOK_SECRET ;
if ( authHeader !== expectedToken ) {
return res . status ( 401 ). json ({ error: 'Unauthorized' });
}
next ();
}
app . post ( '/webhook/hamsa' , verifyToken , async ( req , res ) => {
const event = req . body ;
try {
switch ( event . eventType ) {
case 'call.started' :
await handleCallStarted ( event );
break ;
case 'call.ended' :
await handleCallEnded ( event );
break ;
case 'transcription.update' :
await handleTranscription ( event );
break ;
case 'tool.executed' :
await handleToolExecution ( event );
break ;
}
// Respond quickly to acknowledge receipt
res . status ( 200 ). json ({ received: true });
} catch ( error ) {
console . error ( 'Webhook error:' , error );
// Still return 200 to prevent retries
res . status ( 200 ). json ({ received: true , error: true });
}
});
async function handleCallEnded ( event ) {
const { conversationId , conversationRecording , transcription , outcomeResult } = event . data . data ;
// Extract echoed identifiers
const applicationId = outcomeResult . application_id ;
const userId = outcomeResult . user_id ;
// Extract collected data
const extractedData = {
expectedSalary: outcomeResult . expectedSalary ,
noticePeriod: outcomeResult . noticePeriod ,
sentiment: outcomeResult . sentiment_score
};
// Update your database
await database . calls . update ({
where: { applicationId },
data: {
conversationId ,
recordingUrl: conversationRecording ,
transcript: transcription ,
... extractedData ,
completedAt: new Date ()
}
});
}
from flask import Flask, request, jsonify
import os
app = Flask( __name__ )
def verify_token ():
auth_header = request.headers.get( 'Authorization' )
expected_token = os.environ.get( 'WEBHOOK_SECRET' )
return auth_header == expected_token
@app.route ( '/webhook/hamsa' , methods = [ 'POST' ])
def webhook ():
if not verify_token():
return jsonify({ 'error' : 'Unauthorized' }), 401
event = request.get_json()
try :
event_type = event.get( 'eventType' )
if event_type == 'call.started' :
handle_call_started(event)
elif event_type == 'call.ended' :
handle_call_ended(event)
elif event_type == 'transcription.update' :
handle_transcription(event)
elif event_type == 'tool.executed' :
handle_tool_execution(event)
return jsonify({ 'received' : True }), 200
except Exception as e:
print ( f 'Webhook error: { e } ' )
return jsonify({ 'received' : True , 'error' : True }), 200
def handle_call_ended ( event ):
data = event[ 'data' ][ 'data' ]
conversation_id = data[ 'conversationId' ]
recording_url = data[ 'conversationRecording' ]
transcription = data[ 'transcription' ]
outcome = data[ 'outcomeResult' ]
# Extract echoed identifiers
application_id = outcome.get( 'application_id' )
user_id = outcome.get( 'user_id' )
# Update database
update_database(
application_id = application_id,
conversation_id = conversation_id,
recording_url = recording_url,
transcription = transcription,
outcome = outcome
)
Call Ended Payload Structure
{
"eventType" : "call.ended" ,
"callId" : "call_uuid_12345" ,
"timestamp" : "2024-01-15T14:35:00.000Z" ,
"projectId" : "proj_abc123" ,
"agentId" : "agent_xyz789" ,
"agentName" : "Customer Support Agent" ,
"data" : {
"timestamp" : "2024-01-15T14:35:00.000Z" ,
"data" : {
"conversationId" : "conv-123-abc-456-def" ,
"conversationRecording" : "https://storage.tryhamsa.com/recordings/conv-123.mp3" ,
"transcription" : [
{ "Agent" : "Hello! How can I help you today?" },
{ "User" : "I need help with my order." },
{ "Agent" : "I'd be happy to help. What's your order number?" },
{ "User" : "It's ORD-12345." }
],
"outcomeResult" : {
"application_id" : "12345" ,
"user_id" : "user-789" ,
"session_id" : "sess-abc-def" ,
"order_number" : "ORD-12345" ,
"issue_type" : "order_inquiry" ,
"resolved" : true ,
"sentiment_score" : 0.8
}
}
}
}
Webhook Best Practices
Respond Quickly Return 200 OK within 5 seconds to avoid timeouts
Process Async Queue events for async processing after acknowledging
Implement Idempotency Use callId + eventType + timestamp to detect duplicates
Secure Endpoints Use HTTPS and Bearer token authentication
Error Handling
HTTP Status Codes
Status Meaning Action 200Success Process response 400Bad Request Check request parameters 401Unauthorized Verify API key 403Forbidden Check permissions 404Not Found Verify resource ID 429Rate Limited Wait and retry with backoff 500Server Error Retry with exponential backoff 503Service Unavailable Retry later
Common Error Codes
Error codes are created by adding two pieces of numbers, first piece refers to the system part responsible for that error, and the second is the status code. Status code is always the last three numbers.
Code Description Resolution 10403Invalid or missing API key Check API key format and validity 10404Resource doesn’t exist Verify resource ID 10400Request validation failed Check request body format 10429Too many requests Implement rate limiting
Error Handling Pattern
async function apiRequest ( endpoint , options = {}) {
const maxRetries = 3 ;
let lastError ;
for ( let attempt = 1 ; attempt <= maxRetries ; attempt ++ ) {
try {
const response = await fetch ( `https://api.tryhamsa.com ${ endpoint } ` , {
... options ,
headers: {
'Authorization' : `Token ${ process . env . HAMSA_API_KEY } ` ,
'Content-Type' : 'application/json' ,
... options . headers
}
});
const data = await response . json ();
if ( ! response . ok ) {
// Handle specific error codes
switch ( response . status ) {
case 401 :
throw new AuthenticationError ( 'Invalid API key' );
case 404 :
throw new NotFoundError ( data . error ?. message || 'Resource not found' );
case 429 :
// Rate limited - wait and retry
const retryAfter = response . headers . get ( 'Retry-After' ) || 60 ;
await sleep ( retryAfter * 1000 );
continue ;
case 500 :
case 503 :
// Server error - retry with backoff
if ( attempt < maxRetries ) {
await sleep ( Math . pow ( 2 , attempt ) * 1000 );
continue ;
}
throw new ServerError ( data . error ?. message || 'Server error' );
default :
throw new APIError ( data . error ?. message || 'API request failed' , response . status );
}
}
return data ;
} catch ( error ) {
lastError = error ;
// Don't retry on authentication or validation errors
if ( error instanceof AuthenticationError || error instanceof ValidationError ) {
throw error ;
}
// Retry on network errors
if ( attempt < maxRetries && error . name === 'NetworkError' ) {
await sleep ( Math . pow ( 2 , attempt ) * 1000 );
continue ;
}
}
}
throw lastError ;
}
function sleep ( ms ) {
return new Promise ( resolve => setTimeout ( resolve , ms ));
}
Rate Limiting & Quotas
Rate Limits
Endpoint Type Limit Window Standard APIs 100 requests Per minute Realtime APIs and Websocket Connections 100 requests Per minute
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1609459200
Handling Rate Limits
async function handleRateLimit ( response ) {
if ( response . status === 429 ) {
const retryAfter = response . headers . get ( 'Retry-After' );
const resetTime = response . headers . get ( 'X-RateLimit-Reset' );
// Wait for the specified time
const waitTime = retryAfter
? parseInt ( retryAfter ) * 1000
: ( parseInt ( resetTime ) - Date . now ());
console . log ( `Rate limited. Waiting ${ waitTime } ms before retry...` );
await sleep ( waitTime );
return true ; // Indicates retry is needed
}
return false ;
}
Storage Quotas
Resource Free Tier Starter Tier Creator Tier Pro Tier Business Tier Enterprise Knowledge Base 1 MB 5 MB 10 MB 50 MB 100 MB 300 MB URLs per Item 100 100 100 100 100 100 Agents Unlimited Unlimited Unlimited Unlimited Unlimited Unlimited Phone Numbers Unlimited Unlimited Unlimited Unlimited Unlimited Unlimited
Edge Cases & Best Practices
Network Connectivity Issues
// Implement connection health checks
class ConnectionMonitor {
constructor ( sdk ) {
this . sdk = sdk ;
this . reconnectAttempts = 0 ;
this . maxReconnectAttempts = 5 ;
this . sdk . on ( 'connectionQualityChanged' , ({ quality }) => {
if ( quality === 'lost' ) {
this . handleDisconnection ();
}
});
this . sdk . on ( 'reconnecting' , () => {
console . log ( 'Attempting to reconnect...' );
});
this . sdk . on ( 'reconnected' , () => {
this . reconnectAttempts = 0 ;
console . log ( 'Reconnected successfully' );
});
}
async handleDisconnection () {
if ( this . reconnectAttempts >= this . maxReconnectAttempts ) {
this . notifyUser ( 'Connection lost. Please refresh the page.' );
return ;
}
this . reconnectAttempts ++ ;
const backoffTime = Math . pow ( 2 , this . reconnectAttempts ) * 1000 ;
await sleep ( backoffTime );
try {
await this . sdk . reconnect ();
} catch ( error ) {
this . handleDisconnection ();
}
}
}
Handling Partial Responses
// Handle partial webhook data
function processWebhookPayload ( payload ) {
const { outcomeResult } = payload . data ?. data || {};
// Safely extract with defaults
const data = {
applicationId: outcomeResult ?. application_id ?? null ,
userId: outcomeResult ?. user_id ?? null ,
expectedSalary: outcomeResult ?. expectedSalary ?? 'Not provided' ,
noticePeriod: outcomeResult ?. noticePeriod ?? 'Not provided' ,
sentiment: outcomeResult ?. sentiment_score ?? null
};
// Log missing critical fields
if ( ! data . applicationId ) {
console . warn ( 'Missing application_id in webhook payload' );
}
return data ;
}
Concurrent Request Management
// Use a request queue for concurrent operations
class RequestQueue {
constructor ( maxConcurrent = 5 ) {
this . maxConcurrent = maxConcurrent ;
this . running = 0 ;
this . queue = [];
}
async add ( requestFn ) {
return new Promise (( resolve , reject ) => {
this . queue . push ({ fn: requestFn , resolve , reject });
this . process ();
});
}
async process () {
if ( this . running >= this . maxConcurrent || this . queue . length === 0 ) {
return ;
}
this . running ++ ;
const { fn , resolve , reject } = this . queue . shift ();
try {
const result = await fn ();
resolve ( result );
} catch ( error ) {
reject ( error );
} finally {
this . running -- ;
this . process ();
}
}
}
// Usage
const queue = new RequestQueue ( 3 );
const results = await Promise . all ([
queue . add (() => fetchAgent ( 1 )),
queue . add (() => fetchAgent ( 2 )),
queue . add (() => fetchAgent ( 3 )),
queue . add (() => fetchAgent ( 4 )),
queue . add (() => fetchAgent ( 5 ))
]);
Idempotency for Critical Operations
// Idempotent operation wrapper
async function idempotentOperation ( operationId , operation ) {
const key = `operation: ${ operationId } ` ;
// Check if already processed
const cached = await redis . get ( key );
if ( cached ) {
return JSON . parse ( cached );
}
// Execute operation
const result = await operation ();
// Cache result with TTL
await redis . setex ( key , 86400 , JSON . stringify ( result ));
return result ;
}
// Usage
await idempotentOperation (
`create-agent- ${ sessionId } ` ,
() => createVoiceAgent ( agentConfig )
);
Graceful Degradation
// Fallback strategy for service unavailability
async function callWithFallback ( primaryFn , fallbackFn , options = {}) {
const { timeout = 5000 , retries = 2 } = options ;
for ( let i = 0 ; i <= retries ; i ++ ) {
try {
const result = await Promise . race ([
primaryFn (),
sleep ( timeout ). then (() => { throw new TimeoutError (); })
]);
return result ;
} catch ( error ) {
if ( i === retries ) {
console . warn ( 'Primary service failed, using fallback' );
return fallbackFn ();
}
await sleep ( Math . pow ( 2 , i ) * 1000 );
}
}
}
// Usage
const result = await callWithFallback (
() => fetchFromPrimaryAPI (),
() => fetchFromCachedData (),
{ timeout: 3000 , retries: 2 }
);
Production Deployment Checklist
Security
Reliability
Monitoring
Next Steps
Support
Document Version: 1.0
Last Updated: 2026-01-07
API Version: v2.0.0