Files
sms-client-portal/API.md
Kwesi Banson Jnr c68c007945 Initial commit
2026-03-19 11:03:33 +00:00

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/json
  • Authorization: Bearer <API Key>

The API key is generated when creating an application and stored in applications.api_key.

Pagination

For list endpoints:

  • page (default 0)
  • size (default 20, max 200)
  • sort (default createdAt,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 ACTIVE or INACTIVE.

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/json
  • Authorization: Bearer <API Key>

Request:

{
  "from": "SENDER_ID",
  "to": "2547XXXXXXXX",
  "refId": "client-app-ref-12345",
  "message": "Hello"
}

Notes:

  • refId is the client reference id stored in messages.client_reference_id.
  • The backend generates messageRefId (UUID) stored in messages.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_id using UCM msgId.

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 = status
    • messages.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.