4.2 KiB
SMS Gateway API
All endpoints are JSON over HTTP.
Base URL
- Local:
http://localhost:8080
Authentication (Send SMS)
POST /api/sms/send requires:
Content-Type: application/jsonAuthorization: Bearer <API Key>
The API key is generated when creating an application and stored in applications.api_key.
Pagination
For list endpoints:
page(default0)size(default20, max200)sort(defaultcreatedAt,desc) format:field,asc|desc
Spring returns a Page<T> JSON with fields like content, totalElements, totalPages, etc.
Clients
Create client
POST /api/clients
Request:
{
"name": "Acme Corp",
"email": "contact@acme.com",
"country": "Kenya",
"phoneNumber": "+254700000000"
}
Response 201:
{
"id": 1,
"name": "Acme Corp",
"email": "contact@acme.com",
"country": "Kenya",
"phoneNumber": "+254700000000",
"status": "NEW",
"createdAt": "2026-03-17T06:00:00Z",
"updatedAt": "2026-03-17T06:00:00Z"
}
List clients (paginated)
GET /api/clients?page=0&size=20&sort=createdAt,desc
Get client by id
GET /api/clients/{id}
Update client status (NEW -> ACTIVE/INACTIVE)
PATCH /api/clients/{id}/status
Headers:
Content-Type: application/json
Request:
{
"status": "ACTIVE"
}
Notes:
- Only accepts
ACTIVEorINACTIVE.
Applications
Create application (generates API key)
POST /api/applications
Request:
{
"name": "My SMS App",
"type": "LOCAL",
"orgId": 1
}
Response 201 (includes apiKey):
{
"id": 1,
"name": "My SMS App",
"type": "LOCAL",
"orgId": 1,
"apiKey": "sms_....",
"createdAt": "2026-03-17T06:00:00Z",
"updatedAt": "2026-03-17T06:00:00Z"
}
List applications (paginated)
GET /api/applications?page=0&size=20&sort=createdAt,desc
Note: list responses do not include apiKey.
List applications by client id (paginated)
GET /api/applications/client/{clientId}?page=0&size=20&sort=createdAt,desc
Get application by id
GET /api/applications/{id}
Send SMS
Send SMS (queue message)
POST /api/sms/send
Headers:
Content-Type: application/jsonAuthorization: Bearer <API Key>
Request:
{
"from": "SENDER_ID",
"to": "2547XXXXXXXX",
"refId": "client-app-ref-12345",
"message": "Hello"
}
Notes:
refIdis the client reference id stored inmessages.client_reference_id.- The backend generates
messageRefId(UUID) stored inmessages.internal_reference_id. - When sending to UCM, we submit
refId = messages.internal_reference_id(our UUID) for end-to-end tracking. - The poller later sends NEW messages to UCM and updates
messages.ucm_message_idusing UCMmsgId.
Response 201:
{
"status": "NEW",
"to": "2547XXXXXXXX",
"messageRefId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"created_at": "2026-03-17 09:33:00"
}
UCM Callbacks
Delivery receipts callback (configured on UCM)
POST /api/ucm/delivery-receipts
Headers:
Content-Type: application/json
Payload:
{
"msgId": "tr-29dd2622-c1c4-46f1-93cb-e40452471924",
"from": "2547XXXXXXXX",
"to": "TIARA",
"refId": "TIARA",
"status": "DeliveredToTerminal",
"statusReason": "DeliveredToTerminal",
"deliveryTime": "2019-02-05 18:27:39.878"
}
How it updates messages:
- Looks up by:
messages.ucm_message_id == msgId - Updates:
messages.ucm_delivery_status = statusmessages.delivery_time = deliveryTime- If
status == DeliveredToTerminal:messages.delivery_status = DELIVERED
Messages
List messages (paginated)
GET /api/messages?page=0&size=20&sort=createdAt,desc
List messages by client id (paginated)
GET /api/messages/client/{clientId}?page=0&size=20&sort=createdAt,desc
Error format
Validation errors (400)
{
"type": "about:blank",
"title": "Validation Failed",
"status": 400,
"detail": "Request validation failed",
"errors": [
{ "field": "to", "message": "Recipient (to) is required" }
]
}
Auth errors (401)
Missing or invalid Authorization: Bearer <API Key> returns a ProblemDetail response with status=401.