Eski SMS

API Documentation

Integrate SMS sending, delivery tracking, and contact management into your application with the Eski SMS REST API.

Overview

The Eski SMS API is a RESTful interface for sending transactional and campaign SMS, querying delivery status, and managing contacts. All endpoints return JSON.

Base URL

https://eskisms.com/api/v3

Content type

application/json

Charset

UTF-8

Every path below is relative to that base URL. The legacy /api/http prefix serves the same endpoints with the same payloads, so an integration written against the older platform keeps working unchanged.

Authentication

Every request must present an API key. The preferred form is a Bearer token in the Authorization header.

Example request header
Authorization: Bearer <your_api_token>

For backward compatibility the same key may also be sent as an api_token query parameter, a form field, a JSON body field, or an api_token cookie. The header is checked first, then the query string, cookie, form body, and JSON body.

Same request, key in the body
curl -X POST "https://eskisms.com/api/v3/sms/send" \
  -H "Content-Type: application/json" \
  -d '{
    "api_token": "<your_api_token>",
    "recipient": "255717222303",
    "message": "Hello",
    "sender_id": "YOURID"
  }'

Create and revoke keys in the dashboard under API Keys, where each key can be named for the system that uses it. A request with no key, or a revoked one, answers 401 Unauthorized; a key whose account may not send answers 403 Forbidden.

Response envelope

Every response is wrapped in a consistent envelope. The status field is success, error, or info. The data field contains the payload when the request succeeds.

Success example
{
  "status": "success",
  "message": "Message accepted for delivery",
  "data": {
    "uid": "abc123",
    "to": "255717222303",
    "from": "YOURID",
    "message": "Hello",
    "sms_type": "plain",
    "status": "queued",
    "direction": "api",
    "sms_count": 1,
    "cost": "1",
    "sent_at": "2026-10-16T09:41:12Z"
  }
}
Error example
{
  "status": "error",
  "message": "Sender ID \"SHADOW\" is not authorized to send this message."
}

A send that the network refuses is reported as info with HTTP 200: the request was valid, but the message was not accepted for delivery, and the message field carries the reason.

HTTP status codes

Code Meaning
200Request handled. Check status: success, error (rare on 200) or info.
401Missing or invalid API key.
403The account or API access is not enabled, or the sender ID is not authorized for it.
404The record does not exist, or does not belong to the authenticated account.
422Validation failed: missing recipient, message or sender ID, an unparsable datetime, or insufficient balance.
500Unexpected server error. Safe to retry the read endpoints.
POST

/sms/send

Send a single SMS message to one recipient.

Request body

Field Type Required Description
recipientstringyesDestination phone number in E.164 or local format. Punctuation is ignored; 9–15 digits are accepted.
messagestringyesMessage body. Long messages are split and concatenated automatically.
sender_idstringyesApproved sender ID for your account.
typestringnoMessage type: plain (default) or unicode. otp is accepted and sent as plain.

Example

curl -X POST https://eskisms.com/api/v3/sms/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient": "255717222303",
    "message": "Hello from Eski SMS",
    "sender_id": "YOURID",
    "type": "plain"
  }'

A recipient holding a comma-separated list is treated as a bulk send and answered like /sms/campaign, so one call can address a list. Each number is billed separately; duplicates in the same request are sent once.

POST

/sms/campaign

Send a bulk campaign to multiple recipients.

Request body

Field Type Required Description
recipientstringyesComma-separated list of phone numbers.
messagestringyesCampaign message body.
sender_idstringyesApproved sender ID.
namestringnoCampaign name. Generated automatically if omitted.
typestringnoplain (default) or unicode.

Example

curl -X POST https://eskisms.com/api/v3/sms/campaign \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient": "255717222303,255713000111",
    "message": "Campaign launch",
    "sender_id": "YOURID",
    "name": "Launch Campaign"
  }'
Response
{
  "status": "success",
  "message": "Campaign created successfully",
  "data": {
    "uid": "campaign123",
    "name": "Launch Campaign"
  }
}

The whole campaign is checked against your balance before it is accepted, so a list you cannot afford is refused with 422 instead of being created and then skipped.

GET

/sms

List sent messages for the authenticated user. The default window is the last 30 days, 25 rows per page, in the Laravel paginator shape (data, current_page, last_page, total, links).

Query parameters

Parameter Description
pagePage number (default 1).
start_dateFilter from this datetime (Y-m-d H:i:s).
end_dateFilter up to this datetime (Y-m-d H:i:s).
sms_typeFilter by plain or unicode.
directionFilter by api or outgoing.
timezoneIANA name the dates are interpreted and returned in, e.g. Africa/Dar_es_Salaam. Defaults to the platform timezone.
GET

/sms/:uid

Return one message by its uid, including the SMSC delivery receipt when the network has reported on it. A uid that belongs to another account answers 404.

GET

/delivery-logs

Query delivery logs with the same filters and pagination as /sms. The status parameter narrows the result to one status, for example delivered, rejected or queued.

GET

/delivery-logs/:uid

The delivery detail of one message: its status history and the raw receipt as the network sent it, with the submit and done times.

GET

/campaign/:uid/view

One campaign with its messages, so a bulk send can be followed recipient by recipient.

Message status

A message starts queued, moves through submitted or enroute, and ends delivered — or rejected, undelivered, failed, expired or deleted with the network's error code in the receipt. A status only changes when the network says so: a message with no receipt yet stays queued rather than being reported as delivered.

GET

/contacts

Contact groups and the contacts inside them. Group identifiers are the group uid; the same uid addresses an individual contact.

Method Path Purpose
GET/contactsList contact groups.
POST/contactsCreate a group.
POST/contacts/:uid/showRead one group.
PATCH/contacts/:uidRename a group.
DELETE/contacts/:uidDelete a group.
POST/contacts/:group_id/allList the contacts inside a group.
POST/contacts/:group_id/search/:uidFind one contact in a group.
POST/contacts/:group_id/storeAdd a contact to a group.
PATCH/contacts/:group_id/update/:uidUpdate a contact in a group.
DELETE/contacts/:group_id/delete/:uidRemove a contact from a group.

Example

curl -X POST https://eskisms.com/api/v3/contacts/abc123/store \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "255717222303",
    "first_name": "Amina",
    "last_name": "Juma"
  }'
GET

/me

Return the authenticated account: profile, timezone, locale, and the sender IDs it may use.

GET

/balance

Return the remaining SMS units and the date they expire.

GET

/ping

Confirm the key works and the API is reachable. This is the cheapest endpoint to call from a health check.

Keeping your keys safe

Anyone holding a key can send from your balance, so treat it like a password and never put it in a public repository or a browser-side script. Generate a separate key per system, so one can be revoked without disturbing the others.

A key is shown once when it is created; only a hash is stored and it cannot be displayed again. Lost keys are replaced, not recovered.