Jasmin Compatible API: Keep Your Existing Code When You Switch to Ozeki
The most expensive part of replacing an SMS gateway is not the gateway itself. It is the application work: every script, service and integration that calls the old API has to be found, changed, tested and redeployed. Ozeki SMS Gateway removes this cost. It implements the Jasmin /send HTTP API, so your applications keep sending requests with the same URL path, the same parameters and the same response handling they use today. This page documents the interface from a developer perspective: the request format, a full parameter reference, delivery report callbacks, encoding rules, and code samples in PHP, Python, Java and C# that run against both gateways without modification. For the reasons to switch, see our Jasmin alternative overview. For the cutover procedure, read the migration guide.
API compatibility
When you switch from Jasmin to Ozeki, you throw out Jasmin, and switch to the Jasmin compatible API built into Ozeki SMS Gateway. After migration your apps will connect to Ozeki. It is very crucial to understand the compatibility, and how Ozeki SMS Gateway provides compatible interfaces to your Jasmin apps (Figure 1).
How the Jasmin HTTP API Works
Jasmin exposes message submission through its HTTP API. Applications send an HTTP GET or POST request to the /send path on the configured http-api port, which is 1401 in a default installation. The request carries the credentials of a Jasmin user account, the recipient, the message content, and optional parameters for routing, encoding and delivery reports. Jasmin answers with a plain text body and an HTTP 200 status code. On success the body starts with Success followed by a quoted message id, a UUID assigned to the queued message, for example Success "07033084-5cfd-4812-90a4-e4d24ffb6e3d". This simple contract, a single URL with query parameters, is the reason thousands of applications integrated with Jasmin over the years, and it is exactly the contract Ozeki reproduces.
The Same Request Works on Both Gateways
Suppose your application sends this request to Jasmin today:
http://jasmin.example.com:1401/send?username=myuser&password=secret&to=%2B36201234567&from=MyApp&content=Hello+world
To send the same message through Ozeki, change only the host and port:
http://ozeki.example.com:PORT/send?username=myuser&password=secret&to=%2B36201234567&from=MyApp&content=Hello+world
The path, the parameters and the values are identical. A quick test with curl confirms the response format:
curl "http://ozeki.example.com:PORT/send?username=myuser&password=secret&to=%2B36201234567&from=MyApp&content=Hello+world" Success "07033084-5cfd-4812-90a4-e4d24ffb6e3d"
Ozeki returns the same plain text responses your code already parses: Success "uuid" with HTTP 200 when the message is accepted and queued, Error "No route found" with HTTP 412 when no route matches the message, and Error "Authentication failure for username:myuser" with HTTP 403 when the credentials do not match a user account. The complete set of status codes is listed in the table below.
| HTTP Code | Body | Meaning |
|---|---|---|
| 200 | Success "uuid" | Message accepted and queued, message id returned |
| 400 | Error "Mandatory arguments not found, please refer to the HTTPAPI specifications." | Request validation error |
| 400 | Error "Argument _ is unknown." / "Argument _ has an invalid value: _." | Unknown or invalid parameter |
| 403 | Error "Authentication failure for username:_" | Authentication error |
| 403 | Error "Authorization failed for username:_" | Credentials validation error |
| 403 | Error "Cannot charge submit_sm, check RouterPB log file for details" | User charging (balance) error |
| 412 | Error "No route found" | Message routing error |
| 500 | Error "Cannot send submit_sm, check SMPPClientManagerPB log file for details" | Fallback error, see gateway log for details |
/send Parameter Reference
The table below lists the parameters your applications may use. Ozeki accepts each one with the same meaning, so no request has to be rewritten. Note that username and password identify a user account, and Jasmin users require sufficient credit on their account, so the same quota behaviour applies in Ozeki.
| Parameter | Purpose |
|---|---|
| username, password | Credentials of the Jasmin user account |
| to | Recipient phone number, URL encoded |
| from | Sender address (sender ID or number) |
| content | Message body, URL encoded |
| hex-content | Binary message content in hexadecimal, alternative to content |
| coding | Data coding scheme: 0 (SMSC default / GSM 7 bit), 2 (8 bit binary), 8 (UCS-2), ... |
| priority | Message priority: 0 (lowest), 1, 2 or 3 |
| sdt | Scheduled delivery time in SMPP absolute or relative format |
| validity-period | Validity period in minutes |
| dlr | Delivery report request: yes or no |
| dlr-url | Callback URL that receives the delivery events |
| dlr-level | Report level: 1 (SMSC), 2 (terminal), 3 (both) |
| dlr-method | HTTP method of the callback: GET or POST |
| tags | Message tags for routing and interception logic |
Delivery Report Callbacks: dlr, dlr-url, dlr-level and dlr-method
Delivery reports are the part of the /send contract that applications depend on most. Three parameters control them. dlr=yes enables tracking for the message, dlr-url is the callback URL, dlr-level selects which events trigger a callback, and dlr-method selects whether the callback is an HTTP GET or POST request:
| dlr-level | Event |
|---|---|
| 1 | SMSC level: the report is delivered when the SMSC acknowledges the submit |
| 2 | Terminal level: the report is delivered when the phone acknowledges the message |
| 3 | Both SMSC and terminal level reports are delivered |
When an event occurs, the gateway calls dlr-url and appends the report parameters as name value pairs. The parameters below are always present:
| Parameter | Replaced with |
|---|---|
| id | Internal gateway message id (UUID) |
| message_status | SMPP command status, e.g. ESME_ROK on delivery success |
| level | The dlr-level originally requested |
| connector | The SMPP connector that handled the message |
| id_smsc | Message id returned by the SMSC (level 2 and 3) |
| subdate, donedate | Submission and final state times (level 2 and 3) |
| err | Network or SMSC error code on failure (level 2 and 3) |
| text | First 20 characters of the message (level 2 and 3) |
If your application passes dlr-url=http://app.example.com/dlr, it receives requests like these:
GET /dlr?id=07033084-5cfd-4812-90a4-e4d24ffb6e3d&message_status=ESME_ROK&level=2&connector=myconn&text=Hello+world (delivered) GET /dlr?id=07033084-5cfd-4812-90a4-e4d24ffb6e3d&message_status=ESME_RINVNUMDESTS&level=2&connector=myconn (failed)
One detail catches many developers. The receiving endpoint must acknowledge every callback by replying with HTTP 200 and a body containing exactly ACK/Jasmin. If the acknowledgement is missing, the DLRThrower service considers the delivery failed and retries the callback (by default up to 3 retries with a 30 second delay). Your existing Jasmin receiver already implements this, so it keeps working unchanged. Beyond HTTP callbacks, Ozeki also stores every message and its delivery status internally, which is covered on our Jasmin DLR alternative page.
Character Encoding, Long Messages and Binary Content
Both gateways handle message content the same way:
- coding=0: SMSC default alphabet (GSM 03.38), 7 bit, up to 160 characters per message
- coding=2: 8 bit binary content
- coding=8: UCS-2 (UTF-16) encoding for characters outside the GSM alphabet, 70 characters per part
Text is submitted with the content parameter and binary content with hex-content, for example hex-content=0623063106460628 for a UCS-2 Arabic message. When your text contains characters the GSM alphabet cannot represent, submit it with coding=8, and the gateway converts the text to UCS-2.
Long messages are split into concatenated parts automatically. Jasmin splits by default using a 6 byte User Data Header (long_content_split=udh) and a maximum of 5 parts per message (long_content_max_parts=5); splitting through SAR options is also supported. The same limits and UDH values apply on both gateways, and binary formats such as WAP push messages and port addressed application data are submitted the same way.
Code Samples That Work Unchanged
The following samples send a message and print the gateway response. Each one runs against Jasmin or Ozeki without modification. The only value to adjust is the base URL: point it at your Jasmin host and port today, and at your Ozeki host and port after the migration. The URL encoding functions take care of escaping the dlr-url value described above.
PHP
<?php $baseUrl = "http://ozeki.example.com:PORT/send"; $query = http_build_query([ "username" => "myuser", "password" => "secret", "to" => "+36201234567", "from" => "MyApp", "content" => "Hello from PHP", "dlr" => "yes", "dlr-url" => "http://app.example.com/dlr", "dlr-level" => "2", "dlr-method" => "GET", ]); $response = file_get_contents($baseUrl . "?" . $query); echo $response; // Success "uuid" ?>
Python
import urllib.parse
import urllib.request
params = {
"username": "myuser",
"password": "secret",
"to": "+36201234567",
"from": "MyApp",
"content": "Hello from Python",
"dlr": "yes",
"dlr-url": "http://app.example.com/dlr",
"dlr-level": "2",
"dlr-method": "GET",
}
url = "http://ozeki.example.com:PORT/send?" + urllib.parse.urlencode(params)
with urllib.request.urlopen(url) as response:
print(response.read().decode()) # Success "uuid"
Java
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public class SendSms {
public static void main(String[] args) throws Exception {
String url = "http://ozeki.example.com:PORT/send"
+ "?username=myuser&password=secret"
+ "&to=" + URLEncoder.encode("+36201234567", StandardCharsets.UTF_8)
+ "&from=MyApp"
+ "&content=" + URLEncoder.encode("Hello from Java", StandardCharsets.UTF_8)
+ "&dlr=yes&dlr-url=" + URLEncoder.encode("http://app.example.com/dlr", StandardCharsets.UTF_8)
+ "&dlr-level=2&dlr-method=GET";
HttpURLConnection c = (HttpURLConnection) new URL(url).openConnection();
try (InputStream in = c.getInputStream()) {
System.out.println(new String(in.readAllBytes(), StandardCharsets.UTF_8));
}
}
}
C#
using System;
using System.Net;
using System.Net.Http;
class SendSms
{
static void Main()
{
var url = "http://ozeki.example.com:PORT/send"
+ "?username=myuser&password=secret"
+ "&to=" + Uri.EscapeDataString("+36201234567")
+ "&from=MyApp"
+ "&content=" + Uri.EscapeDataString("Hello from C#")
+ "&dlr=yes&dlr-url=" + Uri.EscapeDataString("http://app.example.com/dlr")
+ "&dlr-level=2&dlr-method=GET";
using var client = new HttpClient();
Console.WriteLine(client.GetStringAsync(url).Result);
// Success "uuid"
}
}
Differences and Optional Ozeki Extensions
The compatibility is deliberate and complete on the application facing side, but a few points are worth knowing before you switch:
- Base URL. The host and port change, the /send path and parameters stay the same.
- Responses. The plain text bodies, including the quoted message id, the route and authentication errors, and the HTTP status codes match the format your code already handles.
- Routing. Jasmin's MT router and connector selection map to routing rules in Ozeki, as described in the migration guide.
- Quotas. Jasmin users require sufficient credit, so user quotas behave the same way in Ozeki.
- Extensions. Ozeki additionally offers its native HTTP API, SQL database messaging, an SMPP server, and a searchable message archive with delivery status. These are optional. Nothing forces you to adopt them during the migration, and your applications can keep using the Jasmin format indefinitely.
During evaluation, test the edge cases your production traffic includes: concatenated messages, UCS-2 text, binary content, and delivery report callbacks with the ACK/Jasmin acknowledgement. All of them can be verified with the free trial (download) before you plan the cutover. The complete reference, including the /balance, /rate and /metrics endpoints, is available on our Jasmin compatible HTTP API page.