Skip to content

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 TypeLimit
API Key endpoints100 requests/minute
Bulk messaging10 requests/minute
Auth endpoints5 attempts/15 minutes

How to Fix:

  • Implement exponential backoff
  • Use the Retry-After header 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 MessageCauseSolution
Phone number must be in E.164 formatInvalid phone formatUse format: +26878422613
Invalid channel. Must be one of: sms, whatsapp, emailInvalid channel valueUse valid channel names
Missing required field: content.textMissing message contentInclude message text
Email already existsDuplicate email on signupUse different email or login
Password must be at least 8 charactersWeak passwordUse stronger password
Invalid date formatDate not in ISO 8601Use: 2025-11-02T12:00:00Z
Limit must be between 1 and 100Invalid pagination limitUse value 1-100

Authentication Errors (401)

Error MessageCauseSolution
Invalid API keyWrong or malformed keyCheck API key value
API key has been deactivatedDeactivated keyCreate new API key
Invalid or expired tokenExpired JWTLogin again
Missing X-API-Key headerNo auth headerAdd authentication header

Payment Errors (402)

Error MessageCauseSolution
Insufficient credits. You need X but have YLow credit balancePurchase credits
Credit purchase failedPayment issueCheck 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:

  1. Check the error message carefully
  2. Verify your request parameters
  3. Review the API Reference
  4. Contact support: [email protected]

Built with VitePress