@smart-pay-chain/otp
v2.1.7
Published
Official TypeScript SDK for Smart Pay Chain OTP Verification Service - Now with phone authentication, JWT tokens, admin support, and brand management
Maintainers
Readme
@smart-pay-chain/otp
Official TypeScript/JavaScript SDK for Smart Pay Chain OTP Verification Service
Website • Documentation • NPM Package • GitHub
Send and verify one-time passwords via SMS, WhatsApp, and Voice with ease.
What's New in v2.1
🆕 Phone Authentication - Complete passwordless auth with JWT tokens
🆕 Admin Role Support - RBAC with USER/ADMIN roles
🆕 Brand Management - Two-stage brand approval workflow
🆕 API Key Handling - Secure key generation and one-time secret reveal
🆕 Backend Integration - Full guide for sms-service integration
What's New in v2.0
🆕 Test Mode - Development-friendly testing with fixed OTP codes and test phone numbers
🆕 Status Endpoints - Check OTP status and get codes for testing
🆕 Auto-Configuration - SDK auto-configures from server settings
🆕 Mobile Examples - Complete React Native integration example
🆕 Idempotency - Automatic idempotency keys for retry safety
🆕 Enhanced Errors - Machine-readable error codes for better handling
Features
✨ Multiple Channels - Send OTPs via SMS, WhatsApp, or Voice
🔒 Secure - Built-in encryption, timing-safe comparisons, and rate limiting
🎯 Type-Safe - Full TypeScript support with comprehensive type definitions
🔄 Retry Logic - Automatic retries for transient failures
📱 Mobile Ready - React Native example and mobile integration guide
🔐 Phone Authentication - Complete passwordless auth with JWT tokens
👥 Admin Support - Role-based access control (RBAC)
🏢 Brand Management - Two-stage approval workflow
🧪 Test Mode - Development testing with fixed codes
📦 Lightweight - Minimal dependencies
🧪 Well-Tested - Comprehensive test coverage
📚 Well-Documented - Extensive documentation and examples
Installation
npm install @smart-pay-chain/otpor
yarn add @smart-pay-chain/otpQuick Start
import { OtpClient, OtpChannel } from '@smart-pay-chain/otp';
// Initialize the client
const client = new OtpClient({
apiKey: 'your-api-key-here',
autoConfig: true, // v2.0: Auto-fetch server configuration
});
// Send an OTP
const result = await client.sendOtp({
phoneNumber: '+995568000865',
channel: OtpChannel.SMS,
});
console.log('OTP sent! Request ID:', result.requestId);
// v2.0: Check status
const status = await client.getStatus(result.requestId);
console.log('Current status:', status.status);
// Verify the OTP
const verification = await client.verifyOtp({
requestId: result.requestId,
code: '123456', // Code entered by user
});
if (verification.success) {
console.log('Phone number verified! ✓');
}Table of Contents
- What's New in v2.0
- Installation
- Quick Start
- Test Mode
- Configuration
- Usage
- Mobile App Integration
- Error Handling
- Idempotency
- API Reference
- Examples
- Migration from v1 to v2
- Testing
- Contributing
- License
Test Mode
Test mode allows you to test OTP flows without sending real SMS messages. Perfect for development and automated testing!
// Check if server is in test mode
const testMode = await client.isTestMode();
if (testMode) {
console.log('Test mode enabled - use test phone numbers');
}
// Use test phone numbers
import { TEST_PHONE_NUMBERS, TEST_OTP_CODE } from '@smart-pay-chain/otp';
const result = await client.sendOtp({
phoneNumber: TEST_PHONE_NUMBERS.SUCCESS, // +15005550006
});
// In test mode, OTP code is always: 123456
const verification = await client.verifyOtp({
requestId: result.requestId,
code: TEST_OTP_CODE, // '123456'
});Test Phone Numbers:
+15005550006- Always succeeds+15005550007- SMS send fails+15005550008- Rate limit exceeded+15005550009- Insufficient balance+15005550010- Brand not authorized
For Development/Testing Only:
// Get actual OTP code (WARNING: Never use in production!)
const status = await client.getStatusWithCode(result.requestId);
console.log('OTP Code:', status.otpCode); // For automated testsConfiguration
Client Options
const client = new OtpClient({
apiKey: 'your-api-key-here', // Required: Your API key
baseUrl: 'https://custom.api.com', // Optional: Custom base URL
timeout: 30000, // Optional: Request timeout (ms)
maxRetries: 3, // Optional: Max retry attempts
autoConfig: true, // Optional: Auto-fetch server config
platform: 'react-native', // Optional: SDK platform
language: 'typescript', // Optional: SDK language
headers: { // Optional: Custom headers
'X-App-Version': '1.0.0',
},
});Usage
Sending OTP
Send an OTP to a phone number using your preferred channel:
const result = await client.sendOtp({
phoneNumber: '+995568000865', // Required: E.164 format
channel: OtpChannel.SMS, // Optional: SMS, WHATSAPP, or VOICE
ttl: 300, // Optional: Time-to-live (60-600 seconds)
length: 6, // Optional: Code length (4-8 digits)
metadata: { // Optional: Custom metadata
userId: 'user_12345',
action: 'login',
},
idempotencyKey: 'unique-key', // Optional: Prevent duplicate sends
});
console.log(result.requestId); // Save this for verification
console.log(result.expiresAt); // When the OTP expires
console.log(result.status); // Current statusVerifying OTP
Verify the OTP code entered by the user:
const result = await client.verifyOtp({
requestId: 'req_123456', // From sendOtp response
code: '123456', // User-entered code
ipAddress: '192.168.1.1', // Optional but recommended
userAgent: 'Mozilla/5.0...', // Optional
});
if (result.success) {
console.log('Verified!', result.message);
// Proceed with authentication
} else {
console.log('Failed:', result.message);
// Show error to user
}Resending OTP
Resend the OTP if the user didn't receive it:
const result = await client.resendOtp({
requestId: 'req_123456',
});
console.log('New request ID:', result.requestId);
console.log('Expires at:', result.expiresAt);Checking Status
Check the current status of an OTP request:
const status = await client.getStatus('req_123456');
console.log('Status:', status.status); // 'PENDING' | 'SENT' | 'VERIFIED' | 'EXPIRED' | 'FAILED'
console.log('Attempts:', status.attempts);
console.log('Max attempts:', status.maxAttempts);
console.log('Is expired:', status.isExpired);
console.log('Expires at:', status.expiresAt);SDK Configuration
Get server configuration (auto-cached for 1 hour):
const config = await client.getConfig();
console.log('OTP config:', config.otpConfig);
console.log('Rate limits:', config.rateLimits);
console.log('Test mode:', config.features.testMode);
console.log('Supported countries:', config.supportedCountries);Mobile App Integration
The SDK is designed to run on your backend server, not directly in mobile apps. This keeps your API keys secure.
See our comprehensive Mobile Apps Guide for:
- React Native integration (complete example)
- Flutter/Dart integration
- iOS native (Swift)
- Android native (Kotlin)
- Passwordless authentication with refresh tokens
- Security best practices
Quick Example:
// Backend API
router.post('/auth/send-otp', async (req, res) => {
const result = await otpClient.sendOtp({
phoneNumber: req.body.phoneNumber,
});
res.json({ requestId: result.requestId });
});
// Mobile app calls your backend
fetch('https://yourapi.com/auth/send-otp', {
method: 'POST',
body: JSON.stringify({ phoneNumber: '+995568000865' }),
});Error Handling
The SDK provides specific error classes for different scenarios:
import {
OtpError,
AuthenticationError,
ValidationError,
RateLimitError,
OtpExpiredError,
InvalidOtpError,
} from '@smart-pay-chain/otp';
try {
const result = await client.verifyOtp({ ... });
} catch (error) {
if (error instanceof InvalidOtpError) {
console.log('Wrong code. Please try again.');
} else if (error instanceof OtpExpiredError) {
console.log('OTP expired. Request a new one.');
} else if (error instanceof RateLimitError) {
console.log('Too many attempts. Please wait.');
} else if (error instanceof OtpError) {
// Generic OTP error
console.log('Error:', error.message);
console.log('Code:', error.code);
console.log('Retryable:', error.retryable);
}
}Error Properties
All OTP errors include:
message: Human-readable error messagecode: Error code (e.g.,OTP_EXPIRED,INVALID_OTP_CODE)statusCode: HTTP status coderetryable: Whether the request can be retrieddetails: Additional error details (optional)requestId: Request ID for debugging (optional)
Idempotency
The SDK automatically generates unique idempotency keys for send/resend operations to prevent duplicate requests:
// Automatic idempotency (recommended)
const result = await client.sendOtp({
phoneNumber: '+995568000865',
// SDK auto-generates: X-Idempotency-Key: {timestamp}-{random}
});
// Manual idempotency key (for custom requirements)
const result = await client.sendOtp({
phoneNumber: '+995568000865',
idempotencyKey: 'my-unique-key-123',
});Benefits:
- Prevents duplicate OTPs on network retries
- Safe for flaky mobile networks
- Automatic for all send/resend operations
API Reference
OtpClient
constructor(config: OtpClientConfig)
Create a new OTP client instance.
sendOtp(options: SendOtpOptions): Promise<SendOtpResponse>
Send an OTP to a phone number.
Parameters:
phoneNumber(string, required): Phone number in E.164 formatchannel(OtpChannel, optional): Delivery channel (default: SMS)ttl(number, optional): Time-to-live in seconds (60-600, default: 300)length(number, optional): OTP code length (4-8, default: 6)metadata(object, optional): Custom metadataidempotencyKey(string, optional): Idempotency key
Returns:
requestId(string): Unique request identifierexpiresAt(Date): Expiration timestampstatus(string): Current status
verifyOtp(options: VerifyOtpOptions): Promise<VerifyOtpResponse>
Verify an OTP code.
Parameters:
requestId(string, required): Request ID from sendOtpcode(string, required): OTP code to verifyipAddress(string, optional): User's IP addressuserAgent(string, optional): User's user agent
Returns:
success(boolean): Whether verification succeededmessage(string): Result message
resendOtp(options: ResendOtpOptions): Promise<SendOtpResponse>
Resend an OTP.
Parameters:
requestId(string, required): Original request ID
Returns:
Same as sendOtp()
getStatus(requestId: string): Promise<OtpStatus>
Get OTP status (authenticated endpoint).
Parameters:
requestId(string, required): Request ID
Returns:
id(string): Request IDphoneNumber(string): Phone number (masked)channel(OtpChannel): Delivery channelstatus(string): Current statusattempts(number): Verification attemptsmaxAttempts(number): Maximum attempts allowedexpiresAt(Date): Expiration timeverifiedAt(Date | null): Verification timecreatedAt(Date): Creation timeisExpired(boolean): Whether OTP is expired
getStatusWithCode(requestId: string): Promise<OtpStatusWithCode>
Get OTP status with code (public endpoint, for testing/development only).
WARNING: This returns the actual OTP code. Only use in test/development!
Returns: Same as getStatus() plus:
otpCode(string): The actual OTP codesmsProvider(string | null): SMS provider usedsmsMessageId(string | null): Provider message ID
getConfig(forceRefresh?: boolean): Promise<SdkConfiguration>
Get SDK configuration from server (cached for 1 hour).
Parameters:
forceRefresh(boolean, optional): Force refresh cached config
Returns: Server configuration including rate limits, features, test mode status, etc.
testConnection(): Promise<boolean>
Test connectivity to the OTP service.
Returns: true if connected, false otherwise
isTestMode(): Promise<boolean>
Check if server is in test mode.
Returns: true if test mode is enabled
Types
OtpChannel
enum OtpChannel {
SMS = 'SMS',
WHATSAPP = 'WHATSAPP',
VOICE = 'VOICE',
}ErrorCode
enum ErrorCode {
AUTHENTICATION_FAILED = 'AUTHENTICATION_FAILED',
INVALID_API_KEY = 'INVALID_API_KEY',
INVALID_PHONE_NUMBER = 'INVALID_PHONE_NUMBER',
OTP_EXPIRED = 'OTP_EXPIRED',
OTP_MAX_ATTEMPTS = 'OTP_MAX_ATTEMPTS',
INVALID_OTP_CODE = 'INVALID_OTP_CODE',
OTP_NOT_FOUND = 'OTP_NOT_FOUND',
RATE_LIMIT_EXCEEDED = 'RATE_LIMIT_EXCEEDED',
// ... and more
}See types.ts for complete type definitions.
Examples
The SDK includes comprehensive examples:
- Basic Usage - Simple send and verify flow
- Advanced Usage - Error handling, metadata, retries
- Test Mode 🆕 - Testing with fixed OTP codes
- Express Integration - Backend API with Express.js
- Phone Authentication 🆕 - Complete passwordless auth with JWT
- React Integration - Frontend form with React
- React Native 🆕 - Mobile app integration
- Mobile Apps Guide 🆕 - Flutter, iOS, Android examples
- Backend Integration Guide 🆕 - Full sms-service integration
See the examples directory for more details.
Migration from v1 to v2
All v1.0 code continues to work in v2.0! No breaking changes.
New Features in v2.0:
// v2.0 additions (optional)
const client = new OtpClient({
apiKey: 'your-key',
autoConfig: true, // NEW: Auto-fetch server config
});
// NEW: Check OTP status
const status = await client.getStatus(requestId);
// NEW: Get OTP code for testing
const testStatus = await client.getStatusWithCode(requestId);
// NEW: Check test mode
const testMode = await client.isTestMode();
// NEW: Test connectivity
const connected = await client.testConnection();Automatic Improvements:
- Idempotency keys auto-generated for all send/resend operations
- SDK version tracking headers automatically included
- Enhanced error codes for better error handling
Testing
Run the test suite:
npm testRun tests in watch mode:
npm run test:watchGenerate coverage report:
npm test -- --coverageBest Practices
Security
- Never expose your API key in frontend code
- Use backend endpoints to proxy OTP requests
- Implement rate limiting on your endpoints
- Use HTTPS for all requests
User Experience
- Show clear error messages to users
- Display OTP expiration time
- Implement resend functionality
- Limit verification attempts (3-5 max)
Production
- Use environment variables for API keys
- Implement proper logging and monitoring
- Handle all error cases gracefully
- Use idempotency keys for critical flows
Requirements
- Node.js >= 16.0.0
- TypeScript >= 5.0.0 (if using TypeScript)
Support
Need help? We're here for you!
- 🌐 Website: smartpaychain.com
- 📚 Documentation: docs.smartpaychain.com
- 🐛 Issues: GitHub Issues
- 📧 Email: [email protected]
- 💬 Community: Join our Discord
Contributing
Contributions are welcome! Please read our Contributing Guide for details.
License
MIT License - see the LICENSE file for details.
Changelog
See CHANGELOG.md for version history.
🏢 About Smart Pay Chain
Smart Pay Chain is a leading provider of blockchain-based payment solutions and verification services.
🌐 smartpaychain.com | 📧 [email protected]
Products & Services
- 🔐 OTP Verification Service (SMS, WhatsApp, Voice)
- 💳 Payment Processing Solutions
- ⛓️ Blockchain Integration Services
- 🔒 Secure Authentication Systems
Made with ❤️ by Smart Pay Chain
© 2025 Smart Pay Chain. All rights reserved.
