API Keys Management
API keys allow you to authenticate API requests programmatically. Learn how to create, manage, and secure your API keys.
Overview
API keys are used for:
- Sending messages via the API
- Retrieving message history
- Accessing message details
SECURITY
API keys are sensitive credentials. Never expose them in client-side code, public repositories, or logs.
Authentication Header
Use API keys in the X-API-Key header:
X-API-Key: ybk_1234567890abcdef...Creating API Keys
API keys can only be created using JWT authentication (after logging in to your workspace).
Endpoint
POST /api/v1/api-keysRequest
curl -X POST https://api.yebolink.com/api/v1/api-keys \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Production API Key",
"scopes": ["send_messages", "read_messages"]
}'const response = await fetch('https://api.yebolink.com/api/v1/api-keys', {
method: 'POST',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Production API Key',
scopes: ['send_messages', 'read_messages']
})
});
const data = await response.json();
console.log('API Key:', data.data.key);
// Save this key securely - it won't be shown again!import requests
import os
response = requests.post(
'https://api.yebolink.com/api/v1/api-keys',
headers={
'Authorization': f'Bearer {jwt_token}',
'Content-Type': 'application/json'
},
json={
'name': 'Production API Key',
'scopes': ['send_messages', 'read_messages']
}
)
data = response.json()
api_key = data['data']['key']
print(f'API Key: {api_key}')
# Save this key securely - it won't be shown again!<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://api.yebolink.com/api/v1/api-keys',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $jwtToken,
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Production API Key',
'scopes' => ['send_messages', 'read_messages']
])
]);
$response = curl_exec($curl);
$data = json_decode($response, true);
echo 'API Key: ' . $data['data']['key'];
// Save this key securely - it won't be shown again!
curl_close($curl);
?>require 'net/http'
require 'json'
require 'uri'
uri = URI('https://api.yebolink.com/api/v1/api-keys')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['Authorization'] = "Bearer #{jwt_token}"
request['Content-Type'] = 'application/json'
request.body = {
name: 'Production API Key',
scopes: ['send_messages', 'read_messages']
}.to_json
response = http.request(request)
data = JSON.parse(response.body)
puts "API Key: #{data['data']['key']}"
# Save this key securely - it won't be shown again!package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
type CreateKeyRequest struct {
Name string `json:"name"`
Scopes []string `json:"scopes"`
}
type CreateKeyResponse struct {
Success bool `json:"success"`
Data struct {
ID string `json:"id"`
Name string `json:"name"`
Key string `json:"key"`
KeyPrefix string `json:"key_prefix"`
Scopes []string `json:"scopes"`
CreatedAt string `json:"created_at"`
Warning string `json:"warning"`
} `json:"data"`
}
func createAPIKey(jwtToken string) (string, error) {
reqBody := CreateKeyRequest{
Name: "Production API Key",
Scopes: []string{"send_messages", "read_messages"},
}
jsonData, _ := json.Marshal(reqBody)
req, _ := http.NewRequest("POST",
"https://api.yebolink.com/api/v1/api-keys",
bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer "+jwtToken)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result CreateKeyResponse
json.Unmarshal(body, &result)
fmt.Println("API Key:", result.Data.Key)
// Save this key securely - it won't be shown again!
return result.Data.Key, nil
}Response
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Production API Key",
"key": "ybk_1234567890abcdef1234567890abcdef1234567890abcdef",
"key_prefix": "ybk_1234567...",
"scopes": ["send_messages", "read_messages"],
"created_at": "2025-11-02T12:00:00Z",
"warning": "Save this key securely. It will not be shown again."
}
}IMPORTANT
The full API key is only shown once when created. Save it immediately in a secure location. If you lose it, you'll need to create a new one.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Descriptive name for the API key |
scopes | array | No | Permissions for the key (defaults to all) |
Available Scopes
| Scope | Description |
|---|---|
send_messages | Send messages via API |
read_messages | Retrieve message history and details |
Listing API Keys
Get all API keys for your workspace.
Endpoint
GET /api/v1/api-keysRequest
curl -X GET https://api.yebolink.com/api/v1/api-keys \
-H "Authorization: Bearer YOUR_JWT_TOKEN"const response = await fetch('https://api.yebolink.com/api/v1/api-keys', {
headers: {
'Authorization': `Bearer ${jwtToken}`
}
});
const data = await response.json();
console.log('API Keys:', data.data.api_keys);import requests
response = requests.get(
'https://api.yebolink.com/api/v1/api-keys',
headers={'Authorization': f'Bearer {jwt_token}'}
)
data = response.json()
for key in data['data']['api_keys']:
print(f"{key['name']}: {key['key_prefix']} (Last used: {key['last_used_at']})")<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://api.yebolink.com/api/v1/api-keys',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $jwtToken
]
]);
$response = curl_exec($curl);
$data = json_decode($response, true);
foreach ($data['data']['api_keys'] as $key) {
echo $key['name'] . ': ' . $key['key_prefix'] . "\n";
}
curl_close($curl);
?>Response
{
"success": true,
"data": {
"api_keys": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Production API Key",
"key_prefix": "ybk_1234567...",
"scopes": ["send_messages", "read_messages"],
"is_active": true,
"last_used_at": "2025-11-02T10:30:00Z",
"created_at": "2025-11-01T12:00:00Z"
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Development API Key",
"key_prefix": "ybk_9876543...",
"scopes": ["send_messages", "read_messages"],
"is_active": true,
"last_used_at": null,
"created_at": "2025-10-15T08:00:00Z"
}
]
}
}TIP
The last_used_at field helps you identify unused keys that can be safely deleted.
Deactivating API Keys
Deactivate an API key to immediately revoke access.
Endpoint
DELETE /api/v1/api-keys/:idRequest
curl -X DELETE https://api.yebolink.com/api/v1/api-keys/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer YOUR_JWT_TOKEN"const keyId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(`https://api.yebolink.com/api/v1/api-keys/${keyId}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${jwtToken}`
}
});
const data = await response.json();
console.log(data.data.message);import requests
key_id = '550e8400-e29b-41d4-a716-446655440000'
response = requests.delete(
f'https://api.yebolink.com/api/v1/api-keys/{key_id}',
headers={'Authorization': f'Bearer {jwt_token}'}
)
data = response.json()
print(data['data']['message'])<?php
$keyId = '550e8400-e29b-41d4-a716-446655440000';
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.yebolink.com/api/v1/api-keys/$keyId",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $jwtToken
]
]);
$response = curl_exec($curl);
$data = json_decode($response, true);
echo $data['data']['message'];
curl_close($curl);
?>Response
{
"success": true,
"data": {
"message": "API key deactivated successfully"
}
}WARNING
Once deactivated, the API key cannot be reactivated. You'll need to create a new key.
Best Practices
1. Store API Keys Securely
Use Environment Variables:
# .env file
YEBOLINK_API_KEY=ybk_1234567890abcdef...// Node.js
require('dotenv').config();
const apiKey = process.env.YEBOLINK_API_KEY;# Python
import os
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv('YEBOLINK_API_KEY')Never hardcode API keys:
// ❌ DON'T DO THIS
const apiKey = 'ybk_1234567890abcdef...';
// ✅ DO THIS
const apiKey = process.env.YEBOLINK_API_KEY;2. Use Different Keys for Different Environments
Create separate API keys for:
- Development
- Staging
- Production
This allows you to:
- Track usage per environment
- Rotate keys without affecting all environments
- Deactivate compromised keys without disrupting production
3. Rotate Keys Regularly
// Key rotation workflow
async function rotateAPIKey(oldKeyId, jwtToken) {
// 1. Create new API key
const newKeyResponse = await fetch('https://api.yebolink.com/api/v1/api-keys', {
method: 'POST',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Production API Key (Rotated)',
scopes: ['send_messages', 'read_messages']
})
});
const newKey = await newKeyResponse.json();
// 2. Update your environment variables
console.log('New API Key:', newKey.data.key);
// Update your .env file or secret manager
// 3. Wait for deployment to complete
await deployNewKey(newKey.data.key);
// 4. Deactivate old key
await fetch(`https://api.yebolink.com/api/v1/api-keys/${oldKeyId}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${jwtToken}`
}
});
console.log('API key rotation complete');
}4. Monitor API Key Usage
Check the last_used_at field regularly:
async function auditAPIKeys(jwtToken) {
const response = await fetch('https://api.yebolink.com/api/v1/api-keys', {
headers: {
'Authorization': `Bearer ${jwtToken}`
}
});
const data = await response.json();
const now = new Date();
const thirtyDaysAgo = new Date(now.setDate(now.getDate() - 30));
data.data.api_keys.forEach(key => {
const lastUsed = key.last_used_at ? new Date(key.last_used_at) : null;
if (!lastUsed || lastUsed < thirtyDaysAgo) {
console.log(`⚠️ Unused key: ${key.name} (${key.key_prefix})`);
console.log(` Consider deactivating if not needed`);
}
});
}5. Implement Rate Limit Handling
class YeboLinkClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseURL = 'https://api.yebolink.com';
}
async request(endpoint, options = {}) {
const response = await fetch(`${this.baseURL}${endpoint}`, {
...options,
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json',
...options.headers
}
});
// Check rate limits
const remaining = response.headers.get('X-RateLimit-Remaining');
const limit = response.headers.get('X-RateLimit-Limit');
if (parseInt(remaining) < 10) {
console.warn(`⚠️ Rate limit warning: ${remaining}/${limit} requests remaining`);
}
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
throw new Error(`Rate limited. Retry after ${retryAfter} seconds`);
}
return response.json();
}
}6. Never Expose API Keys in Client-Side Code
// ❌ NEVER DO THIS - Exposed in browser
const sendMessage = async (to, text) => {
const response = await fetch('https://api.yebolink.com/api/v1/messages/send', {
method: 'POST',
headers: {
'X-API-Key': 'ybk_1234567890abcdef...' // EXPOSED TO USERS!
},
body: JSON.stringify({ to, channel: 'sms', content: { text } })
});
};
// ✅ DO THIS - API key stays on server
// Frontend:
const sendMessage = async (to, text) => {
const response = await fetch('/api/send-message', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ to, text })
});
};
// Backend (Node.js/Express):
app.post('/api/send-message', async (req, res) => {
const { to, text } = req.body;
const response = await fetch('https://api.yebolink.com/api/v1/messages/send', {
method: 'POST',
headers: {
'X-API-Key': process.env.YEBOLINK_API_KEY // Safe on server
},
body: JSON.stringify({
to,
channel: 'sms',
content: { text }
})
});
const data = await response.json();
res.json(data);
});Security Checklist
- [ ] Store API keys in environment variables
- [ ] Never commit API keys to version control
- [ ] Use different keys for dev/staging/prod
- [ ] Rotate keys every 90 days
- [ ] Monitor key usage regularly
- [ ] Deactivate unused keys
- [ ] Never expose keys in client-side code
- [ ] Implement proper error handling
- [ ] Use HTTPS for all API requests
- [ ] Log API key usage for audit trails
Troubleshooting
"Invalid API key" Error
Possible causes:
- API key is incorrect or malformed
- API key has been deactivated
- Wrong authentication header
Solution:
// Verify API key format
console.log('API Key starts with "ybk_":', apiKey.startsWith('ybk_'));
// Check key is active
const response = await fetch('https://api.yebolink.com/api/v1/api-keys', {
headers: {
'Authorization': `Bearer ${jwtToken}`
}
});
const data = await response.json();
const activeKeys = data.data.api_keys.filter(k => k.is_active);
console.log('Active keys:', activeKeys.map(k => k.key_prefix));Rate Limit Exceeded
Solution:
async function sendWithBackoff(messageData, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
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 delay = Math.pow(2, i) * 1000; // Exponential backoff
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
return await response.json();
}
throw new Error('Max retries exceeded');
}Need Help?
- Check the API Reference
- Review Error Handling
- Contact support: support@yebolink.app