Error Handling
Understanding API errors and how to handle them
Error Handling
The BizCARE MyInvois API uses conventional HTTP response codes to indicate the success or failure of an API request. This guide explains the error codes, their meanings, and how to handle them effectively.
HTTP Status Codes
Success Codes
| Code | Status | Description |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created successfully |
202 | Accepted | Request accepted for processing |
204 | No Content | Request succeeded, no content returned |
Client Error Codes
| Code | Status | Description |
|---|---|---|
400 | Bad Request | Invalid request format or parameters |
401 | Unauthorized | Authentication required or invalid |
403 | Forbidden | Access denied |
404 | Not Found | Resource not found |
406 | Not Acceptable | Request format not acceptable |
409 | Conflict | Resource conflict (e.g., duplicate invoice code) |
422 | Unprocessable Entity | Validation errors |
Server Error Codes
| Code | Status | Description |
|---|---|---|
500 | Internal Server Error | Server encountered an error |
502 | Bad Gateway | Invalid response from upstream server |
503 | Service Unavailable | Service temporarily unavailable |
504 | Gateway Timeout | Request timeout |
Error Response Format
All error responses follow a consistent JSON format:
{
"error": "error_type",
"message": "Human-readable error message",
"details": {
"field": "Additional error details"
}
}Error Response Fields
| Field | Type | Description |
|---|---|---|
error | string | Error type identifier |
message | string | Human-readable error description |
details | object | Additional error information (optional) |
Common Error Types
Authentication Errors
401 Unauthorized - Missing Authentication
{
"error": "Unauthorized",
"message": "Authentication required"
}Cause: No authentication header provided
Solution: Include X-API-Key or Authorization header
401 Unauthorized - Invalid Credentials
{
"error": "Unauthorized",
"message": "Invalid API key"
}Cause: Invalid or expired API key/token Solution: Check your API key or refresh your token
403 Forbidden - Access Denied
{
"error": "Access token is missing or invalid",
"message": "You don't have permission to access this resource"
}Cause: Valid authentication but insufficient permissions Solution: Check your account permissions or contact support
Validation Errors
422 Unprocessable Entity - Field Validation
{
"error": "validation_error",
"message": "The given data was invalid",
"details": {
"invoice_code": ["The invoice code field is required"],
"buyer.name": ["The buyer name field is required"],
"line_items.0.quantity": ["The quantity must be greater than 0"]
}
}Cause: Required fields missing or invalid data format
Solution: Check the details object for specific field errors
400 Bad Request - Invalid Format
{
"error": "Bad Request",
"message": "Invalid JSON format"
}Cause: Malformed JSON in request body Solution: Validate your JSON syntax
Business Logic Errors
409 Conflict - Duplicate Invoice Code
{
"success": false,
"message": "Invoice code already exists"
}Cause: Attempting to create an invoice with an existing invoice code Solution: Use the validation endpoint to check uniqueness first
403 Forbidden - Invoice Cannot Be Modified
{
"success": false,
"message": "Invoice cannot be updated"
}Cause: Trying to modify an invoice that has already been submitted Solution: Only draft orders can be modified
403 Forbidden - Invoice Cannot Be Deleted
{
"success": false,
"message": "Invoice cannot be deleted"
}Cause: Trying to delete an invoice that has been submitted Solution: Only draft orders can be deleted
Resource Errors
404 Not Found - Invoice
{
"error": "Invoice not found",
"message": "The requested invoice does not exist"
}Cause: Invoice ID doesn't exist or doesn't belong to your company Solution: Verify the invoice ID and your access permissions
404 Not Found - Company
{
"message": "Company not found"
}Cause: Company not found or not accessible Solution: Complete company setup or check permissions
External Service Errors
400 Bad Request - TIN Validation
{
"error": "invalid_tin",
"error_description": "The provided TIN is not valid",
"error_uri": "https://docs.example.com/validation/tin"
}Cause: Invalid TIN format or TIN not found in government database Solution: Verify TIN format and check with Malaysian tax authorities
500 Internal Server Error - MyInvois Integration
{
"error": "Internal server error",
"message": "Failed to connect to MyInvois service"
}Cause: MyInvois service unavailable or integration error Solution: Retry the request or contact support if the issue persists
Error Handling Best Practices
1. Always Check Status Codes
const response = await fetch('/api/orders', {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify(orderData)
});
if (!response.ok) {
const error = await response.json();
console.error('API Error:', error);
// Handle error based on status code
switch (response.status) {
case 401:
// Handle authentication error
break;
case 422:
// Handle validation errors
break;
case 409:
// Handle conflict (duplicate invoice code)
break;
default:
// Handle other errors
}
}2. Handle Validation Errors
if (response.status === 422) {
const error = await response.json();
if (error.details) {
// Display field-specific errors
Object.keys(error.details).forEach(field => {
console.error(`${field}: ${error.details[field].join(', ')}`);
});
}
}3. Implement Retry Logic
async function apiRequest(url, options, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.ok) {
return response;
}
// Don't retry client errors (4xx)
if (response.status >= 400 && response.status < 500) {
throw new Error(`Client error: ${response.status}`);
}
// Retry server errors (5xx)
if (attempt === maxRetries) {
throw new Error(`Server error after ${maxRetries} attempts`);
}
// Wait before retrying
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
}
}
}4. Log Errors for Debugging
function logError(error, context) {
console.error('API Error:', {
timestamp: new Date().toISOString(),
context,
error: {
status: error.status,
message: error.message,
details: error.details
}
});
}Rate Limiting
When you exceed rate limits, you'll receive a 429 Too Many Requests response:
{
"error": "rate_limit_exceeded",
"message": "Too many requests. Please try again later.",
"retry_after": 3600
}Rate Limit Headers
All responses include rate limiting information:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200Handling Rate Limits
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
// Wait and retry
setTimeout(() => {
// Retry the request
}, retryAfter * 1000);
}Troubleshooting Guide
Common Issues and Solutions
| Issue | Possible Causes | Solutions |
|---|---|---|
| 401 Unauthorized | Invalid API key, expired token | Check API key, refresh token |
| 422 Validation Error | Missing required fields, invalid data | Review field requirements, validate data |
| 409 Conflict | Duplicate invoice code | Use unique invoice codes, check validation endpoint |
| 500 Server Error | Service unavailable, integration issues | Retry request, contact support |
Debug Checklist
- ✅ Check API Key: Ensure your API key is valid and properly formatted
- ✅ Verify Request Format: Confirm JSON syntax and required headers
- ✅ Validate Data: Check all required fields and data formats
- ✅ Check Permissions: Ensure your account has necessary permissions
- ✅ Review Rate Limits: Check if you've exceeded rate limits
- ✅ Test with Minimal Data: Try with the simplest possible request first
Error Logging: Always log errors with sufficient context for debugging, but avoid logging sensitive information like API keys.
Retry Strategy: Implement exponential backoff for retries to avoid overwhelming the server.