Documentation Index Fetch the complete documentation index at: https://docs.monei.cc/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Proper error handling is essential for building reliable applications on Monei infrastructure. This guide covers all error types, response formats, recovery strategies, and best practices.
What you’ll learn:
Error response structure
Common error types and codes
Error handling patterns
Retry strategies
Debugging techniques
Error Response Structure
All Monei API errors follow a consistent format:
{
"statusCode" : 400 ,
"message" : "Insufficient balance for transaction" ,
"error" : {
"details" : {
"required" : 150.50 ,
"available" : 100.00 ,
"currency" : "USDT"
}
}
}
Response Fields
Field Type Description statusCodenumber HTTP status code (400, 401, 403, 404, 429, 500) messagestring Human-readable error description errorstring Error category detailsobject Additional error context (optional)
HTTP Status Codes
Client Errors (4xx)
Server Errors (5xx)
400 Bad Request
Invalid request parameters
Malformed JSON
Missing required fields
401 Unauthorized
Invalid API key
Expired token
Missing authentication
403 Forbidden
Insufficient permissions
KYC tier limit exceeded
Operation not allowed
404 Not Found
Resource doesn’t exist
Invalid endpoint
Transaction not found
429 Too Many Requests
Rate limit exceeded
Too many requests per minute
Retry after specified time
500 Internal Server Error
Unexpected server error
Database connection failure
Processing error
502 Bad Gateway
Upstream service error
Blockchain RPC failure
Third-party API down
503 Service Unavailable
Maintenance mode
Temporary outage
System overload
504 Gateway Timeout
Request timeout
Slow blockchain confirmation
External service timeout
Common Error Types
Authentication Errors
import MoneiSDK from 'monei-sdk' ;
try {
const monei = new MoneiSDK ({
apiKey: process . env . MONEI_API_KEY ,
});
const account = await monei . user . me ();
} catch ( error ) {
if ( error . statusCode === 401 ) {
console . error ( 'Authentication failed' );
console . error ( 'Reason:' , error . message );
// Common causes:
// - Invalid API key
// - Expired session
// - Missing credentials
// Solution: Verify API key and regenerate if needed
}
}
Error Code: UNAUTHORIZED
Common Messages:
“Invalid API key”
“API key expired”
“Missing authentication header”
Solutions:
Verify API key is correct
Check environment variable
Regenerate API key if compromised
Ensure proper header format: x-api-key: YOUR_KEY
Insufficient Balance
try {
const tx = await monei . evm . sendToken ({
to: '0xRecipientAddress' ,
tokenAddress: '0xUSDTAddress' ,
amount: '1000' ,
chainId: 56
});
} catch ( error ) {
if ( error . code === 'INSUFFICIENT_BALANCE' ) {
console . error ( 'Not enough funds' );
console . error ( 'Required:' , error . details . required );
console . error ( 'Available:' , error . details . available );
// Check both token balance and gas balance
const balance = await monei . evm . getBalance ({
tokenAddress: '0xUSDTAddress' ,
chainId: 56
});
const gasBalance = await monei . evm . getBalance ({
tokenAddress: 'native' , // BNB for BSC
chainId: 56
});
console . log ( 'Token balance:' , balance . amount );
console . log ( 'Gas balance:' , gasBalance . amount );
}
}
Error Code: INSUFFICIENT_BALANCE
Common Causes:
Not enough token balance
Insufficient native token for gas
Reserved balance from pending transactions
Solutions:
Check available balance vs. required amount
Ensure enough native token for gas fees
Wait for pending transactions to complete
Fund wallet before retrying
Invalid Recipient
try {
const tx = await monei . evm . sendToken ({
to: 'invalid-address' ,
tokenAddress: '0xUSDTAddress' ,
amount: '100' ,
chainId: 56
});
} catch ( error ) {
if ( error . code === 'INVALID_RECIPIENT' ) {
console . error ( 'Invalid recipient address' );
console . error ( 'Reason:' , error . details . reason );
// Validate address before sending
const isValid = await monei . evm . validateAddress ({
address: recipientAddress ,
chainId: 56
});
if ( ! isValid . valid ) {
console . error ( 'Address validation failed:' , isValid . reason );
// Reasons: wrong format, wrong network, contract without ABI
}
}
}
Error Code: INVALID_RECIPIENT
Common Causes:
Malformed address format
Wrong network for address
Contract address without ABI
Checksum mismatch
Solutions:
Validate address format before sending
Verify network matches recipient
Use address validation endpoint
Double-check copy/paste
KYC Limit Exceeded
try {
const swap = await monei . offramp . swap ({
token: 'USDC' ,
amount: 500000 , // Exceeds tier limit
network: 'polygon' ,
fiatCurrency: 'NGN' ,
bankCode: 'GTBINGLA' ,
accountNumber: '0123456789'
});
} catch ( error ) {
if ( error . code === 'KYC_LIMIT_EXCEEDED' ) {
console . error ( 'Transaction exceeds KYC limits' );
// Check current limits
const limits = await monei . user . getKycLimits ();
console . log ( 'Current Tier:' , limits . tier );
console . log ( 'Daily Limit:' , limits . dailyLimit );
console . log ( 'Used Today:' , limits . dailyUsed );
console . log ( 'Remaining:' , limits . dailyLimit - limits . dailyUsed );
// Suggest upgrade
console . log ( 'Upgrade to Tier' , limits . nextTier , 'for higher limits' );
}
}
Error Code: KYC_LIMIT_EXCEEDED
Limits by Tier:
Tier 1: ₦200,000/day
Tier 2: ₦500,000/day
Tier 3: ₦2,000,000/day
Solutions:
Check remaining daily limit
Split transaction across multiple days
Upgrade KYC tier
Use smaller amounts
Rate Limit Exceeded
try {
const transactions = await monei . transactions . getAll ();
} catch ( error ) {
if ( error . statusCode === 429 ) {
console . error ( 'Rate limit exceeded' );
// Get retry information
const retryAfter = error . headers [ 'retry-after' ]; // seconds
const limit = error . headers [ 'x-ratelimit-limit' ];
const remaining = error . headers [ 'x-ratelimit-remaining' ];
const reset = error . headers [ 'x-ratelimit-reset' ]; // timestamp
console . log ( `Retry after ${ retryAfter } seconds` );
console . log ( `Rate limit: ${ limit } requests/minute` );
// Implement exponential backoff
await new Promise ( resolve =>
setTimeout ( resolve , retryAfter * 1000 )
);
// Retry request
const transactions = await monei . transactions . getAll ();
}
}
Error Code: RATE_LIMIT_EXCEEDED
Rate Limits:
Free tier: 100 requests/minute
Paid plans: 1,000 requests/minute
Burst allowance: 2x limit for 10 seconds
Solutions:
Implement exponential backoff
Cache frequently accessed data
Use webhooks instead of polling
Upgrade plan for higher limits
Network Errors
try {
const tx = await monei . evm . sendToken ({ ... });
} catch ( error ) {
if ( error . code === 'NETWORK_ERROR' ) {
console . error ( 'Blockchain network error' );
console . error ( 'Network:' , error . details . network );
console . error ( 'Reason:' , error . details . reason );
// Common network errors:
// - RPC timeout
// - Network congestion
// - Gas price too low
// - Nonce mismatch
// Retry with exponential backoff
const maxRetries = 3 ;
for ( let i = 0 ; i < maxRetries ; i ++ ) {
try {
const tx = await monei . evm . sendToken ({ ... });
break ; // Success
} catch ( retryError ) {
if ( i === maxRetries - 1 ) throw retryError ;
await new Promise ( r => setTimeout ( r , Math . pow ( 2 , i ) * 1000 ));
}
}
}
}
Error Code: NETWORK_ERROR
Common Causes:
RPC endpoint timeout
Network congestion
Gas price estimation failure
Blockchain node issues
Solutions:
Implement retry with exponential backoff
Increase gas price
Try different RPC endpoint
Wait for network congestion to clear
Error Handling Patterns
Try-Catch Pattern
async function safeTransfer ( params ) {
try {
const tx = await monei . evm . sendToken ( params );
return { success: true , data: tx };
} catch ( error ) {
console . error ( 'Transaction failed:' , error . message );
// Log error details
console . error ( 'Status:' , error . statusCode );
console . error ( 'Code:' , error . code );
console . error ( 'Details:' , error . details );
// Return error info
return {
success: false ,
error: {
message: error . message ,
code: error . code ,
recoverable: isRecoverable ( error )
}
};
}
}
function isRecoverable ( error ) {
const recoverableCodes = [
'NETWORK_ERROR' ,
'RATE_LIMIT_EXCEEDED' ,
'NETWORK_CONGESTION'
];
return recoverableCodes . includes ( error . code );
}
Retry with Exponential Backoff
async function retryWithBackoff (
fn ,
maxRetries = 3 ,
baseDelay = 1000
) {
for ( let attempt = 0 ; attempt < maxRetries ; attempt ++ ) {
try {
return await fn ();
} catch ( error ) {
const isLastAttempt = attempt === maxRetries - 1 ;
const isRetryable = isRecoverable ( error );
if ( isLastAttempt || ! isRetryable ) {
throw error ;
}
const delay = baseDelay * Math . pow ( 2 , attempt );
console . log ( `Retry attempt ${ attempt + 1 } after ${ delay } ms` );
await new Promise ( resolve => setTimeout ( resolve , delay ));
}
}
}
// Usage
const tx = await retryWithBackoff (
() => monei . evm . sendToken ({ ... }),
3 ,
1000
);
Circuit Breaker Pattern
class CircuitBreaker {
constructor ( threshold = 5 , timeout = 60000 ) {
this . failureCount = 0 ;
this . threshold = threshold ;
this . timeout = timeout ;
this . state = 'CLOSED' ; // CLOSED, OPEN, HALF_OPEN
this . nextAttempt = Date . now ();
}
async execute ( fn ) {
if ( this . state === 'OPEN' ) {
if ( Date . now () < this . nextAttempt ) {
throw new Error ( 'Circuit breaker is OPEN' );
}
this . state = 'HALF_OPEN' ;
}
try {
const result = await fn ();
this . onSuccess ();
return result ;
} catch ( error ) {
this . onFailure ();
throw error ;
}
}
onSuccess () {
this . failureCount = 0 ;
this . state = 'CLOSED' ;
}
onFailure () {
this . failureCount ++ ;
if ( this . failureCount >= this . threshold ) {
this . state = 'OPEN' ;
this . nextAttempt = Date . now () + this . timeout ;
}
}
}
// Usage
const breaker = new CircuitBreaker ( 5 , 60000 );
try {
const tx = await breaker . execute (
() => monei . evm . sendToken ({ ... })
);
} catch ( error ) {
console . error ( 'Circuit breaker prevented call or call failed' );
}
Validation Before Requests
Validate inputs before making API calls to catch errors early:
function validateTransferParams ( params ) {
const errors = [];
// Validate address
if ( ! params . to || params . to . length !== 42 ) {
errors . push ( 'Invalid recipient address' );
}
// Validate amount
if ( ! params . amount || parseFloat ( params . amount ) <= 0 ) {
errors . push ( 'Amount must be greater than 0' );
}
// Validate chainId
const validChains = [ 1 , 56 , 137 , 8453 , 42161 , 10 ];
if ( ! validChains . includes ( params . chainId )) {
errors . push ( 'Invalid chain ID' );
}
if ( errors . length > 0 ) {
throw new Error ( `Validation failed: ${ errors . join ( ', ' ) } ` );
}
return true ;
}
// Use before API call
validateTransferParams ({
to: '0xRecipientAddress' ,
amount: '100' ,
chainId: 56
});
const tx = await monei . evm . sendToken ({ ... });
Debugging Tips
Node.js: const monei = new MoneiSDK ({
apiKey: process . env . MONEI_API_KEY ,
debug: true // Enables detailed logging
});
Python: import logging
logging.basicConfig( level = logging. DEBUG )
monei = MoneiClient(
api_key = os.getenv( 'MONEI_API_KEY' ),
debug = True
)
Log full error objects: try {
await monei . evm . sendToken ({ ... });
} catch ( error ) {
console . error ( 'Full error object:' , JSON . stringify ( error , null , 2 ));
console . error ( 'Stack trace:' , error . stack );
}
Check response headers: console . log ( 'Rate limit remaining:' , error . headers [ 'x-ratelimit-remaining' ]);
console . log ( 'Request ID:' , error . headers [ 'x-request-id' ]);
Always test error scenarios in sandbox: const monei = new MoneiSDK ({
apiKey: process . env . MONEI_SANDBOX_KEY ,
environment: 'sandbox'
});
// Test insufficient balance
// Test invalid addresses
// Test rate limits
Best Practices
Validate Early Validate all inputs before making API calls to catch errors early
Handle Gracefully Show user-friendly error messages, not raw API errors
Implement Retries Use exponential backoff for transient errors
Log Everything Log errors with full context for debugging
Next Steps
Testing Test error scenarios in sandbox environment
Webhooks Get real-time error notifications
Support Contact support for help with errors
FAQ Common questions and solutions