REST API
SMS Sender Proxy — REST API Reference
Base URL: http://<host>:8088
Authentication
JWT (Bearer Token)
Used by: /api/v1/dashboard/*, /api/v1/settings/*, /api/v1/smpp/*, /api/v1/sms/*
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <jwt_token> |
X-App-ID | Yes | Numeric application ID |
Error responses:
| Status | Body | Reason |
|---|---|---|
401 | {"error": "authorization header required"} | Missing Authorization |
401 | {"error": "X-App-ID header required"} | Missing X-App-ID |
400 | {"error": "invalid X-App-ID"} | Non-numeric X-App-ID |
401 | {"error": "unknown app_id"} | App not found |
401 | {"error": "invalid or expired token"} | JWT verification failed |
Admin Key
Used by: /api/v1/admin/*
| Header | Required | Description |
|---|---|---|
X-Admin-Key | Yes | Shared secret (ADMIN_API_KEY env) |
Error responses:
| Status | Body | Reason |
|---|---|---|
503 | {"error": "admin API key not configured"} | Server not configured |
401 | {"error": "invalid or missing admin key"} | Wrong or missing key |
Rate Limiting
- L1 — Global rate limiter, applied to all requests before routing.
- L2 — Per-app rate limiter, applied only to
/api/v1/sms/*endpoints (after JWT).
1. Monitoring (Public)
GET /healthy
Health check / liveness probe.
Response 200:
{ "status": "ok" }
GET /metrics
Prometheus metrics. Returns text/plain; version=0.0.4.
GET /dashboard/stats
Real-time system statistics for the dashboard (public, no auth).
Response 200:
{
"success": true,
"data": {
"rps": {
"current": 1200,
"data": [
{
"time": "14:30",
"rps": 1150.0
}
]
},
"errors": {
"rate": 0.5,
"data": [
{
"time": "14:30",
"errors": 3,
"rate": 0.26
}
]
},
"topCampaignStats": [
{
"index": 1,
"name": "campaign-abc",
"short_name": "campaign-abc",
"messages": 54321
}
],
"system": {
"cpu": 23.4,
"ram": 65.0,
"disk": 41.2
}
}
}
| Status | Reason |
|---|---|
200 | OK |
500 | Failed to get top campaigns |
2. Auth — /api/v1/user
No authentication required.
POST /api/v1/user/register
Register a new user.
Request:
{"email": "user@example.com", "password": "secret"}
Response 201:
{ "user_id": 42, "error": "" }
| Status | Reason |
|---|---|
201 | Created |
400 | Missing fields / user exists |
500 | Internal error |
POST /api/v1/user/login
Authenticate and receive JWT token.
Request:
{"email": "user@example.com", "password": "secret", "app_id": 1}
Response 200:
{ "token": "eyJhbGciOi...", "error": "" }
| Status | Reason |
|---|---|
200 | OK |
400 | Missing fields / failed to login |
401 | Invalid email or password |
POST /api/v1/user/validate
Check if a user has admin privileges.
Request:
{ "user_id": 42 }
Response 200:
{ "is_admin": true, "error": "" }
| Status | Reason |
|---|---|
200 | OK |
400 | Invalid / zero ID |
500 | Internal error |
POST /api/v1/user/delete
Delete a non-admin user.
Request:
{ "user_id": 42 }
Response 200:
{ "result": true, "error": "" }
| Status | Reason |
|---|---|
200 | Deleted |
400 | Zero ID / user is admin |
404 | User not found |
500 | Failed to check admin status |
3. Dashboard — /api/v1/dashboard (JWT)
GET /api/v1/dashboard/metrics
Aggregate dashboard metrics.
Response 200:
{
"success": true,
"data": {
"total_messages": 1234567,
"total_companies": 45,
"active_connections": 12
}
}
GET /api/v1/dashboard/stats
Same as public GET /dashboard/stats (see above), but JWT-protected.
GET /api/v1/dashboard/smpp-links
List all SMPP links with current status.
Response 200:
{
"success": true,
"data": [
{
"id": 1,
"name": "smpp-link-1",
"status": "LOADED",
"current_tps": 100,
"limit_tps": 100,
"enabled": true
}
]
}
GET /api/v1/dashboard/load-balancers
List load balancer pools.
Response 200:
{
"success": true,
"data": [
{
"id": 0,
"name": "pool-1",
"links": [
"smpp-link-1",
"smpp-link-2"
],
"total_tps": 200
}
]
}
All dashboard endpoints return 500 on service failure.
4. Settings — /api/v1/settings (JWT)
GET /api/v1/settings/license
Get current license information.
Response 200:
{
"success": true,
"data": {
"company": "UNIQUBIC Corporation",
"valid_until": "2025-12-31",
"max_connections": 100,
"max_tps": 1000,
"status": "active"
}
}
POST /api/v1/settings/license/upload
Upload a new license file.
Request: multipart/form-data with field license (file).
Response 200:
{
"success": true,
"message": "License uploaded successfully",
"data": {
"company": "UNIQUBIC Corporation",
"valid_until": "2026-12-31",
"max_connections": 100,
"max_tps": 1000,
"status": "active"
}
}
| Status | Reason |
|---|---|
200 | Uploaded |
400 | No file / bad format |
GET /api/v1/settings/smpp-config
Read-only SMPP connection configuration.
Response 200:
{
"success": true,
"data": [
{
"host": "smpp.example.com",
"port": 2775,
"system_id": "my_system",
"system_type": "client",
"interface_version": "3.4",
"response_timeout": 5
}
]
}
5. SMPP Control — /api/v1/smpp (JWT)
PUT /api/v1/smpp/:id/toggle
Enable or disable an SMPP link.
Request:
{"enabled": false, "reason": "maintenance window"}
Response 200:
{"success": true, "data": { "id": 1, "name": "smpp-link-1", "enabled": false }}
| Status | Reason |
|---|---|
200 | Toggled |
400 | Invalid ID or request body |
500 | Link not found / error |
6. SMS Gateway — /api/v1/sms (JWT + L2 Rate Limit)
POST /api/v1/sms/send
Send an SMS message through the SMPP gateway.
Request:
{
"esme": 1,
"source": "+123456789",
"destination": "+987654321",
"message": "Hello world",
"transaction_id": "tx-001"
}
Response 200:
{
"success": true,
"error": "",
"esme": 1,
"transaction_id": "tx-001",
"message_id": "msg-uuid",
"status": "submitted",
"sms_ids": [
"sms-001",
"sms-002"
],
"task_id": 12345
}
| Status | Reason |
|---|---|
200 | Sent |
400 | Invalid request body |
403 | IP not allowed |
500 | Service / SMPP error |
POST /api/v1/sms/check-esme
Verify ESME connection status.
Request:
{ "esme": 1 }
Response 200:
{"persist": true, "system_id": "my_system", "error": ""}
POST /api/v1/sms/info
Get SMS delivery status.
Request:
{ "esme": 1, "message_id": "msg-uuid"}
Response 200:
{
"message_id": "msg-uuid",
"mode": "submit_sm",
"parts": {
"1": "delivered"
},
"delivered_count": 1,
"sent_at": 1700000000,
"updated_at": 1700000010,
"transaction_id": "tx-001",
"task_id": 12345,
"status": "delivered",
"error": ""
}
| Status | Reason |
|---|---|
200 | OK |
400 | Invalid request |
403 | IP not allowed |
404 | Message not found |
500 | Service error |
7. Admin Panel — /api/v1/admin (Admin Key)
All admin endpoints require the X-Admin-Key header.
Dashboard (mirrors JWT-protected dashboard)
| Method | Path | Same as |
|---|---|---|
| GET | /api/v1/admin/dashboard/metrics | /api/v1/dashboard/metrics |
| GET | /api/v1/admin/dashboard/smpp-links | /api/v1/dashboard/smpp-links |
| GET | /api/v1/admin/dashboard/load-balancers | /api/v1/dashboard/load-balancers |
Campaign Metrics
GET /api/v1/admin/metrics/campaigns
Paginated campaign metrics from Aerospike.
Query params:
| Param | Default | Max | Description |
|---|---|---|---|
page | 1 | — | Page number |
limit | 50 | 100 | Items per page |
Response 200:
{
"success": true,
"data": [
{
"campaign_uuid": "abc-123",
"messages_sent": 1000,
"messages_failed": 5,
"messages_total": 1005,
"sme": 1
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 120,
"totalPages": 3
}
}
Settings (mirrors JWT-protected settings + server-config)
| Method | Path | Same as |
|---|---|---|
| GET | /api/v1/admin/settings/license | /api/v1/settings/license |
| POST | /api/v1/admin/settings/license/upload | /api/v1/settings/license/upload |
| GET | /api/v1/admin/settings/smpp-config | /api/v1/settings/smpp-config |
GET /api/v1/admin/settings/server-config
Full server configuration (admin-only).
Response 200:
{
"success": true,
"data": {
"env": "production",
"server_name": "sms-proxy-01",
"endpoint": "0.0.0.0:8088",
"tls": false,
"storage": {
"db_path": "/data/sms.db"
},
"aerospike": {
"hosts": "aero-1.local",
"port": 3000,
"namespace": "sms",
"sweep_time": "1h0m0s",
"ttl": "86400s"
},
"security": {
"token_ttl": "24h0m0s"
},
"grpc": {
"port": 50051,
"timeout": "5s"
},
"smpp": {
"rules_loaded": true
},
"filters": {
"filter_name": {
"active": true,
"blacklist": false,
"description": "Filter description",
"snippet": "code snippet"
}
},
"statistic_exporter": {
"enabled": true,
"target": "export.example.com",
"bucket": "sms-stats",
"tls": true
},
"monitoring": {
"otel": true,
"sampling": 0.1,
"collector": "otel-collector:4317"
}
}
}
SMPP Control (mirrors JWT-protected)
| Method | Path | Same as |
|---|---|---|
| PUT | /api/v1/admin/smpp/:id/toggle | /api/v1/smpp/:id/toggle |
Proxy Users Management
GET /api/v1/admin/proxy-users/
List all proxy users (SQLite).
Response 200:
{
"success": true,
"data": [
{
"id": 1,
"email": "api-user@example.com",
"is_admin": false,
"app_id": 10,
"app_name": "my-app",
"app_secret": "secret-hash"
}
]
}
POST /api/v1/admin/proxy-users/register
Create a new proxy user with application.
Request:
{
"email": "api-user@example.com",
"password": "strongpass",
"app_name": "my-app",
"app_secret": "my-secret"
}
Response 201:
{"success": true, "data": { "user_id": 42 }}
| Status | Reason |
|---|---|
201 | Created |
400 | Missing fields / duplicate user |
DELETE /api/v1/admin/proxy-users/:id
Delete a proxy user.
Response 200:
{ "success": true }
| Status | Reason |
|---|---|
200 | Deleted |
400 | Invalid ID / error |
PUT /api/v1/admin/proxy-users/:id/toggle-admin
Toggle admin role for a proxy user.
Response 200:
{"success": true, "data": { "id": 42, "is_admin": true }}
| Status | Reason |
|---|---|
200 | Toggled |
400 | Invalid ID |
500 | Service error |
Endpoint Summary
| # | Method | Path | Auth | Handler Package | |
|---|---|---|---|---|---|
| 1 | GET | /healthy | — | monitoringhandler | |
| 2 | GET | /metrics | — | monitoringhandler | |
| 3 | GET | /dashboard/stats | Admin Key | dashboardhandler | |
| 4 | POST | /api/v1/user/register | Admin Key | authhandler | |
| 5 | POST | /api/v1/user/login | — | authhandler | |
| 6 | POST | /api/v1/user/validate | Admin Key | authhandler | |
| 7 | POST | /api/v1/user/delete | Admin Key | authhandler | |
| 8 | GET | /api/v1/dashboard/metrics | JWT | dashboardhandler | |
| 9 | GET | /api/v1/dashboard/stats | JWT | dashboardhandler | |
| 10 | GET | /api/v1/dashboard/smpp-links | JWT | dashboardhandler | |
| 11 | GET | /api/v1/dashboard/load-balancers | JWT | dashboardhandler | |
| 12 | GET | /api/v1/settings/license | JWT | settingshandler | |
| 13 | POST | /api/v1/settings/license/upload | JWT | settingshandler | |
| 14 | GET | /api/v1/settings/smpp-config | JWT | settingshandler | |
| 15 | PUT | /api/v1/smpp/:id/toggle | JWT | smpphandler | |
| 16 | POST | /api/v1/sms/check-esme | JWT + L2 | smshandler | |
| 17 | POST | /api/v1/sms/send | JWT + L2 | smshandler | |
| 18 | POST | /api/v1/sms/info | JWT + L2 | smshandler | |
| 19 | GET | /api/v1/admin/dashboard/metrics | Admin Key | dashboardhandler | |
| 20 | GET | /api/v1/admin/dashboard/smpp-links | Admin Key | dashboardhandler | |
| 21 | GET | /api/v1/admin/dashboard/load-balancers | Admin Key | dashboardhandler | |
| 22 | GET | /api/v1/admin/metrics/campaigns | Admin Key | metricshandler | |
| 23 | GET | /api/v1/admin/settings/license | Admin Key | settingshandler | |
| 24 | POST | /api/v1/admin/settings/license/upload | Admin Key | settingshandler | |
| 25 | GET | /api/v1/admin/settings/server-config | Admin Key | settingshandler | |
| 26 | GET | /api/v1/admin/settings/smpp-config | Admin Key | settingshandler | |
| 27 | PUT | /api/v1/admin/smpp/:id/toggle | Admin Key | smpphandler | |
| 28 | GET | /api/v1/admin/proxy-users/ | Admin Key | proxyuserhandler | |
| 29 | POST | /api/v1/admin/proxy-users/register | Admin Key | proxyuserhandler | |
| 30 | DELETE | /api/v1/admin/proxy-users/:id | Admin Key | proxyuserhandler | |
| 31 | PUT | /api/v1/admin/proxy-users/:id/toggle-admin | Admin Key | proxyuserhandler |