Skip to content

Send SMS Messages

Send SMS messages to recipients worldwide using YeboLink's messaging API.

Endpoint

POST /api/v1/messages/send

Authentication

Requires API Key authentication via X-API-Key header.

Request Body

ParameterTypeRequiredDescription
tostringYesRecipient phone number in E.164 format (e.g., +1234567890)
channelstringYesMust be "sms" for SMS messages
contentobjectYesMessage content object
content.textstringYesThe message text (max 1600 characters)
metadataobjectNoCustom metadata for tracking (key-value pairs)

Try It Now

Send SMS Message

Your API key is stored locally and never sent to our servers. Get an API key →

Example Request

bash
curl -X POST https://api.yebolink.com/api/v1/messages/send \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ybk_live_your_api_key" \
  -d '{
    "to": "+1234567890",
    "channel": "sms",
    "content": {
      "text": "Hello! Your verification code is 123456. Valid for 10 minutes."
    },
    "metadata": {
      "user_id": "12345",
      "purpose": "verification"
    }
  }'
javascript
const sendSMS = async (to, message) => {
  const response = await fetch('https://api.yebolink.com/api/v1/messages/send', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.YEBOLINK_API_KEY
    },
    body: JSON.stringify({
      to,
      channel: 'sms',
      content: {
        text: message
      },
      metadata: {
        user_id: '12345',
        purpose: 'verification'
      }
    })
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message);
  }

  return await response.json();
};

// Usage
try {
  const result = await sendSMS(
    '+1234567890',
    'Hello! Your verification code is 123456. Valid for 10 minutes.'
  );
  console.log('Message sent:', result.data.message_id);
  console.log('Credits used:', result.data.credits_used);
} catch (error) {
  console.error('Failed to send SMS:', error.message);
}
python
import os
import requests

def send_sms(to: str, message: str, metadata: dict = None):
    """Send SMS message via YeboLink"""

    api_key = os.environ.get('YEBOLINK_API_KEY')

    response = requests.post(
        'https://api.yebolink.com/api/v1/messages/send',
        headers={
            'X-API-Key': api_key
        },
        json={
            'to': to,
            'channel': 'sms',
            'content': {
                'text': message
            },
            'metadata': metadata or {}
        }
    )

    response.raise_for_status()
    return response.json()

# Usage
try:
    result = send_sms(
        to='+1234567890',
        message='Hello! Your verification code is 123456. Valid for 10 minutes.',
        metadata={
            'user_id': '12345',
            'purpose': 'verification'
        }
    )

    print(f"Message sent: {result['data']['message_id']}")
    print(f"Credits used: {result['data']['credits_used']}")
except requests.exceptions.HTTPError as e:
    print(f"Failed to send SMS: {e.response.json()['message']}")
php
<?php

function sendSMS($to, $message, $metadata = []) {
    $apiKey = getenv('YEBOLINK_API_KEY');

    $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 => [
            'Content-Type: application/json',
            "X-API-Key: $apiKey"
        ],
        CURLOPT_POSTFIELDS => json_encode([
            'to' => $to,
            'channel' => 'sms',
            'content' => [
                'text' => $message
            ],
            'metadata' => $metadata
        ])
    ]);

    $response = curl_exec($curl);
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    curl_close($curl);

    if ($httpCode !== 201) {
        $error = json_decode($response, true);
        throw new Exception($error['message']);
    }

    return json_decode($response, true);
}

// Usage
try {
    $result = sendSMS(
        '+1234567890',
        'Hello! Your verification code is 123456. Valid for 10 minutes.',
        [
            'user_id' => '12345',
            'purpose' => 'verification'
        ]
    );

    echo "Message sent: " . $result['data']['message_id'] . "\n";
    echo "Credits used: " . $result['data']['credits_used'] . "\n";
} catch (Exception $e) {
    echo "Failed to send SMS: " . $e->getMessage() . "\n";
}
?>
ruby
require 'net/http'
require 'json'
require 'uri'

def send_sms(to, message, metadata = {})
  api_key = ENV['YEBOLINK_API_KEY']
  uri = URI('https://api.yebolink.com/api/v1/messages/send')

  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true

  request = Net::HTTP::Post.new(uri.path)
  request['Content-Type'] = 'application/json'
  request['X-API-Key'] = api_key
  request.body = {
    to: to,
    channel: 'sms',
    content: {
      text: message
    },
    metadata: metadata
  }.to_json

  response = http.request(request)

  if response.code.to_i != 201
    error = JSON.parse(response.body)
    raise "Failed to send SMS: #{error['message']}"
  end

  JSON.parse(response.body)
end

# Usage
begin
  result = send_sms(
    '+1234567890',
    'Hello! Your verification code is 123456. Valid for 10 minutes.',
    { user_id: '12345', purpose: 'verification' }
  )

  puts "Message sent: #{result['data']['message_id']}"
  puts "Credits used: #{result['data']['credits_used']}"
rescue => e
  puts "Error: #{e.message}"
end
go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
)

type SMSRequest struct {
    To       string                 `json:"to"`
    Channel  string                 `json:"channel"`
    Content  map[string]string      `json:"content"`
    Metadata map[string]string      `json:"metadata,omitempty"`
}

type SMSResponse struct {
    Success bool `json:"success"`
    Data    struct {
        MessageID   string `json:"message_id"`
        Status      string `json:"status"`
        CreditsUsed int    `json:"credits_used"`
        CreatedAt   string `json:"created_at"`
    } `json:"data"`
}

func sendSMS(to, message string, metadata map[string]string) (*SMSResponse, error) {
    apiKey := os.Getenv("YEBOLINK_API_KEY")
    url := "https://api.yebolink.com/api/v1/messages/send"

    payload := SMSRequest{
        To:      to,
        Channel: "sms",
        Content: map[string]string{
            "text": message,
        },
        Metadata: metadata,
    }

    jsonPayload, err := json.Marshal(payload)
    if err != nil {
        return nil, err
    }

    req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonPayload))
    if err != nil {
        return nil, err
    }

    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-API-Key", apiKey)

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    if resp.StatusCode != 201 {
        return nil, fmt.Errorf("failed to send SMS: %s", string(body))
    }

    var result SMSResponse
    err = json.Unmarshal(body, &result)
    if err != nil {
        return nil, err
    }

    return &result, nil
}

func main() {
    result, err := sendSMS(
        "+1234567890",
        "Hello! Your verification code is 123456. Valid for 10 minutes.",
        map[string]string{
            "user_id": "12345",
            "purpose": "verification",
        },
    )

    if err != nil {
        fmt.Printf("Failed to send SMS: %v\n", err)
        return
    }

    fmt.Printf("Message sent: %s\n", result.Data.MessageID)
    fmt.Printf("Credits used: %d\n", result.Data.CreditsUsed)
}

Response

Success Response (201 Created)

json
{
  "success": true,
  "data": {
    "message_id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "queued",
    "credits_used": 1,
    "created_at": "2025-11-02T12:00:00Z"
  }
}

Response Fields:

FieldTypeDescription
message_idstringUnique identifier for the message
statusstringCurrent message status (queued, sent, delivered, failed)
credits_usednumberNumber of credits deducted for this message
created_atstringISO 8601 timestamp when message was created

Message Statuses

Your SMS goes through several statuses:

StatusDescription
queuedMessage is queued for sending
sentMessage has been sent to the carrier
deliveredMessage was successfully delivered to recipient
failedMessage delivery failed

Track status changes using webhooks for real-time updates.

Error Responses

Invalid Phone Number (400)

json
{
  "success": false,
  "error": "validation_error",
  "message": "Phone number must be in E.164 format (e.g., +1234567890)"
}

Insufficient Credits (402)

json
{
  "success": false,
  "error": "insufficient_credits",
  "message": "Not enough credits. You need 1 credits but have 0."
}

Invalid API Key (401)

json
{
  "success": false,
  "error": "unauthorized",
  "message": "Invalid or missing API key"
}

Rate Limit Exceeded (429)

json
{
  "success": false,
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Please try again later."
}

Phone Number Format

E.164 Format Required

Always use E.164 format for phone numbers: +[country code][number]

Valid Examples:

  • US: +1234567890
  • UK: +441234567890
  • South Africa: +27123456789
  • Lesotho: +26878422613

Invalid Examples:

  • 1234567890 (missing +)
  • 001234567890 (incorrect prefix)
  • +1 (234) 567-890 (contains spaces/punctuation)

Message Length & Encoding

GSM-7 Encoding (Standard)

Most English text uses GSM-7 encoding:

  • Single SMS: 160 characters
  • Concatenated SMS: 153 characters per part (7 characters used for concatenation headers)

Example:

  • 160 characters = 1 SMS = 1 credit
  • 161-306 characters = 2 SMS = 2 credits
  • 307-459 characters = 3 SMS = 3 credits

Unicode (UCS-2) Encoding

Messages with emojis or special characters use Unicode:

  • Single SMS: 70 characters
  • Concatenated SMS: 67 characters per part

Triggers Unicode:

  • Emojis (😀, 🎉, ❤️)
  • Special characters (Arabic, Chinese, etc.)
  • Some punctuation (", ", —)

Best Practices

1. Validate Phone Numbers

Always validate phone numbers before sending:

javascript
function isValidE164(phoneNumber) {
  const e164Regex = /^\+[1-9]\d{1,14}$/;
  return e164Regex.test(phoneNumber);
}

if (!isValidE164(phoneNumber)) {
  throw new Error('Invalid phone number format');
}

2. Handle Errors Gracefully

Implement retry logic with exponential backoff:

javascript
async function sendSMSWithRetry(to, message, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await sendSMS(to, message);
    } catch (error) {
      if (error.response?.status === 429) {
        // Rate limited - wait and retry
        await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
        continue;
      }
      throw error; // Don't retry other errors
    }
  }
  throw new Error('Max retries exceeded');
}

3. Use Metadata for Tracking

Add metadata to track messages in your system:

javascript
await sendSMS('+1234567890', 'Your code is 123456', {
  user_id: '12345',
  purpose: 'verification',
  campaign_id: 'onboarding_2025',
  environment: 'production'
});

4. Monitor Credits

Check your balance regularly:

javascript
const checkCredits = async () => {
  const response = await fetch('https://api.yebolink.com/api/v1/account', {
    headers: {
      'Authorization': `Bearer ${jwt_token}`
    }
  });
  const data = await response.json();
  console.log('Credits remaining:', data.data.credits_balance);
};

5. Use Webhooks

Set up webhooks to receive delivery confirmations:

javascript
// Your webhook endpoint
app.post('/webhooks/yebolink', (req, res) => {
  const { event, data } = req.body;

  if (event === 'message.delivered') {
    console.log(`Message ${data.message_id} delivered to ${data.recipient}`);
    // Update your database
  } else if (event === 'message.failed') {
    console.log(`Message ${data.message_id} failed: ${data.error_message}`);
    // Handle failure
  }

  res.status(200).send('OK');
});

Use Cases

OTP/Verification Codes

javascript
const sendOTP = async (phoneNumber, code) => {
  return await sendSMS(
    phoneNumber,
    `Your verification code is ${code}. Valid for 10 minutes. Do not share this code.`,
    { purpose: 'otp', code }
  );
};

Order Notifications

javascript
const sendOrderConfirmation = async (phoneNumber, orderNumber) => {
  return await sendSMS(
    phoneNumber,
    `Your order #${orderNumber} has been confirmed! Track your delivery at example.com/track/${orderNumber}`,
    { purpose: 'order_confirmation', order_id: orderNumber }
  );
};

Appointment Reminders

javascript
const sendAppointmentReminder = async (phoneNumber, appointmentTime) => {
  return await sendSMS(
    phoneNumber,
    `Reminder: Your appointment is scheduled for ${appointmentTime}. Reply CANCEL to reschedule.`,
    { purpose: 'appointment_reminder' }
  );
};

Marketing Messages

javascript
const sendPromotionalSMS = async (phoneNumber, promoCode) => {
  return await sendSMS(
    phoneNumber,
    `Special offer! Get 20% off with code ${promoCode}. Valid until midnight. Shop now: example.com`,
    { purpose: 'marketing', campaign: 'flash_sale_nov' }
  );
};

Credits & Pricing

  • Cost: 1 credit per SMS (160 characters)
  • Concatenated Messages: Each segment costs 1 credit
  • Example: A 320-character message = 3 SMS segments = 3 credits

See Billing for credit packages and pricing.

Next Steps

Built with VitePress