Error Handling
Complete guide to understanding and handling YeboLink API errors effectively.
Error Response Format
All error responses follow this consistent structure:
json
{
"success": false,
"error": "Human-readable error message"
}HTTP Status Codes
400 Bad Request
Invalid request parameters or validation errors.
Common Causes:
- Missing required fields
- Invalid phone number format
- Invalid email format
- Invalid date format
- Invalid enum values
Example:
json
{
"success": false,
"error": "Phone number must be in E.164 format (e.g., +26878422613)"
}bash
curl -X POST https://api.yebolink.com/api/v1/messages/send \
-H "X-API-Key: ybk_your_key" \
-H "Content-Type: application/json" \
-d '{
"to": "invalid_phone",
"channel": "sms",
"content": { "text": "Hello" }
}'How to Fix:
- Validate phone numbers using E.164 format:
+[country_code][number] - Check required fields in request body
- Ensure enum values match accepted values
- Use proper date formats (ISO 8601)
401 Unauthorized
Authentication failed or missing credentials.
Common Causes:
- Missing API key or JWT token
- Invalid API key
- Expired JWT token
- Deactivated API key
Example:
json
{
"success": false,
"error": "Invalid API key"
}bash
curl -X POST https://api.yebolink.com/api/v1/messages/send \
-H "X-API-Key: ybk_invalid_key" \
-H "Content-Type: application/json" \
-d '{
"to": "+26878422613",
"channel": "sms",
"content": { "text": "Hello" }
}'How to Fix:
- Verify your API key is correct
- Check that the API key hasn't been deactivated
- For JWT: Login again to get a fresh token
- Ensure you're using the correct authentication method for the endpoint
402 Payment Required
Insufficient credits to complete the operation.
Common Causes:
- Credit balance is zero or too low
- Attempted bulk send without enough credits
Example:
json
{
"success": false,
"error": "Insufficient credits. You need 100 credits but have 50."
}javascript
try {
const response = await fetch('https://api.yebolink.com/api/v1/messages/bulk', {
method: 'POST',
headers: {
'X-API-Key': 'ybk_your_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
channel: 'sms',
content: { text: 'Hello {{name}}' },
recipients: [...100_recipients]
})
});
if (response.status === 402) {
// Redirect user to purchase credits
window.location.href = '/billing';
}
} catch (error) {
console.error(error);
}How to Fix:
- Purchase more credits via the dashboard
- Check your credit balance before sending
- Implement credit balance checks in your application
403 Forbidden
Valid authentication but insufficient permissions.
Common Causes:
- API key doesn't have required scopes
- Trying to access another workspace's resources
Example:
json
{
"success": false,
"error": "API key does not have required scope: manage_webhooks"
}How to Fix:
- Create a new API key with correct scopes
- Verify you're accessing resources from your own workspace
404 Not Found
The requested resource doesn't exist.
Common Causes:
- Invalid message ID
- Message doesn't belong to your workspace
- Webhook, contact, or API key not found
Example:
json
{
"success": false,
"error": "Message not found"
}python
import requests
response = requests.get(
'https://api.yebolink.com/api/v1/messages/invalid-uuid',
headers={'X-API-Key': 'ybk_your_key'}
)
if response.status_code == 404:
print("Message not found")
elif response.ok:
data = response.json()
print(data)How to Fix:
- Verify the resource ID is correct
- Ensure the resource belongs to your workspace
- Check that the resource hasn't been deleted
429 Too Many Requests
Rate limit exceeded.
Common Causes:
- Sending too many requests too quickly
- Exceeding bulk send rate limits
- Too many failed authentication attempts
Example:
json
{
"success": false,
"error": "Rate limit exceeded. Try again in 30 seconds."
}javascript
async function sendWithRetry(messageData, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch('https://api.yebolink.com/api/v1/messages/send', {
method: 'POST',
headers: {
'X-API-Key': process.env.YEBOLINK_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(messageData)
});
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || '30';
const delay = parseInt(retryAfter) * 1000;
console.log(`Rate limited. Retrying in ${retryAfter} seconds...`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
return await response.json();
} catch (error) {
if (i === maxRetries - 1) throw error;
}
}
}Rate Limits:
| Endpoint Type | Limit |
|---|---|
| API Key endpoints | 100 requests/minute |
| Bulk messaging | 10 requests/minute |
| Auth endpoints | 5 attempts/15 minutes |
How to Fix:
- Implement exponential backoff
- Use the
Retry-Afterheader value - Batch requests where possible
- Use bulk endpoints instead of multiple single requests
500 Internal Server Error
Server-side error occurred.
Common Causes:
- Temporary service disruption
- Database connection issues
- Third-party provider errors (Twilio, Stripe, etc.)
Example:
json
{
"success": false,
"error": "Internal server error. Please try again later."
}How to Fix:
- Retry the request after a short delay
- If the error persists, contact support
- Check the status page for known issues
Error Codes Reference
Validation Errors (400)
| Error Message | Cause | Solution |
|---|---|---|
Phone number must be in E.164 format | Invalid phone format | Use format: +26878422613 |
Invalid channel. Must be one of: sms, whatsapp, email | Invalid channel value | Use valid channel names |
Missing required field: content.text | Missing message content | Include message text |
Email already exists | Duplicate email on signup | Use different email or login |
Password must be at least 8 characters | Weak password | Use stronger password |
Invalid date format | Date not in ISO 8601 | Use: 2025-11-02T12:00:00Z |
Limit must be between 1 and 100 | Invalid pagination limit | Use value 1-100 |
Authentication Errors (401)
| Error Message | Cause | Solution |
|---|---|---|
Invalid API key | Wrong or malformed key | Check API key value |
API key has been deactivated | Deactivated key | Create new API key |
Invalid or expired token | Expired JWT | Login again |
Missing X-API-Key header | No auth header | Add authentication header |
Payment Errors (402)
| Error Message | Cause | Solution |
|---|---|---|
Insufficient credits. You need X but have Y | Low credit balance | Purchase credits |
Credit purchase failed | Payment issue | Check payment method |
Best Practices
1. Always Check Response Status
javascript
const response = await fetch('https://api.yebolink.com/api/v1/messages/send', {
method: 'POST',
headers: {
'X-API-Key': process.env.YEBOLINK_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(messageData)
});
if (!response.ok) {
const error = await response.json();
throw new Error(`API Error (${response.status}): ${error.error}`);
}
const data = await response.json();python
import requests
response = requests.post(
'https://api.yebolink.com/api/v1/messages/send',
headers={'X-API-Key': os.environ['YEBOLINK_API_KEY']},
json=message_data
)
if not response.ok:
error_data = response.json()
raise Exception(f"API Error ({response.status_code}): {error_data['error']}")
data = response.json()php
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://api.yebolink.com/api/v1/messages/send',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . getenv('YEBOLINK_API_KEY'),
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode($messageData)
]);
$response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($httpCode !== 200 && $httpCode !== 201) {
$error = json_decode($response, true);
throw new Exception("API Error ($httpCode): " . $error['error']);
}
$data = json_decode($response, true);
?>go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
type ErrorResponse struct {
Success bool `json:"success"`
Error string `json:"error"`
}
func sendMessage(data map[string]interface{}) error {
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST",
"https://api.yebolink.com/api/v1/messages/send",
bytes.NewBuffer(jsonData))
req.Header.Set("X-API-Key", os.Getenv("YEBOLINK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 && resp.StatusCode != 201 {
var errResp ErrorResponse
body, _ := io.ReadAll(resp.Body)
json.Unmarshal(body, &errResp)
return fmt.Errorf("API Error (%d): %s", resp.StatusCode, errResp.Error)
}
return nil
}2. Implement Retry Logic
javascript
async function apiCallWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
// Don't retry client errors (4xx except 429)
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
throw new Error(`Client error: ${response.status}`);
}
// Retry on 429 or 5xx
if (response.status === 429 || response.status >= 500) {
if (attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
}
return await response.json();
} catch (error) {
if (attempt === maxRetries - 1) throw error;
}
}
}3. Validate Data Before Sending
javascript
function validatePhoneNumber(phone) {
// E.164 format: +[country code][number]
const e164Regex = /^\+[1-9]\d{1,14}$/;
return e164Regex.test(phone);
}
function validateMessageData(data) {
if (!data.to || !validatePhoneNumber(data.to)) {
throw new Error('Invalid phone number. Use E.164 format: +26878422613');
}
if (!['sms', 'whatsapp', 'email'].includes(data.channel)) {
throw new Error('Invalid channel. Must be: sms, whatsapp, or email');
}
if (!data.content || !data.content.text) {
throw new Error('Message text is required');
}
}4. Handle Specific Error Types
javascript
async function sendMessage(messageData) {
try {
const response = await fetch('https://api.yebolink.com/api/v1/messages/send', {
method: 'POST',
headers: {
'X-API-Key': process.env.YEBOLINK_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(messageData)
});
const data = await response.json();
switch (response.status) {
case 200:
case 201:
return data;
case 400:
console.error('Validation error:', data.error);
// Fix the data and retry
break;
case 401:
console.error('Authentication failed:', data.error);
// Refresh API key
break;
case 402:
console.error('Insufficient credits:', data.error);
// Redirect to billing
break;
case 429:
console.error('Rate limited:', data.error);
// Implement backoff and retry
break;
case 500:
console.error('Server error:', data.error);
// Retry after delay
break;
default:
console.error('Unexpected error:', response.status, data.error);
}
throw new Error(data.error);
} catch (error) {
console.error('Request failed:', error);
throw error;
}
}Testing Errors
You can test error handling using invalid data:
bash
# Test 400 - Invalid phone number
curl -X POST https://api.yebolink.com/api/v1/messages/send \
-H "X-API-Key: ybk_your_key" \
-H "Content-Type: application/json" \
-d '{"to": "invalid", "channel": "sms", "content": {"text": "Test"}}'
# Test 401 - Invalid API key
curl -X POST https://api.yebolink.com/api/v1/messages/send \
-H "X-API-Key: invalid_key" \
-H "Content-Type: application/json" \
-d '{"to": "+26878422613", "channel": "sms", "content": {"text": "Test"}}'Need Help?
If you encounter an error not covered here:
- Check the error message carefully
- Verify your request parameters
- Review the API Reference
- Contact support: [email protected]