GENIQ REST API Reference
Welcome to the GENIQ Cloud Communications developer reference. Our APIs allow you to deliver global SMS marketing messages and secure multi-factor validation codes instantly over carrier networks.
This portal describes the REST structures, parameter definitions, and response behavior. All endpoints are secured via HTTPS, returning JSON response envelopes standardly.
đź’ˇ Base Server URL
https://api.geniq.io/rest/v1
// All requests are made via HTTPS.
// Data is passed as URL-encoded form parameters or query strings.
// Responses are returned standardly in JSON.
{
"responseCode": "0",
"responseMessage": "Success"
}
Authentication
All API requests sent to GENIQ servers require authentication. First, authenticate using your API key and secret via HTTP Basic Auth to get a temporary access token. Subsequently, pass this token in the header of each request using the Bearer token scheme.
Before generating the access token, you must first access our console to create an API key and secret. Once generated, combine them in the format API_KEY:SECRET, encode it in Base64, and pass it in the Authorization: Basic [BASE64] header of the token request.
API Authorization Schemes
| Scheme | Header Format | Usage |
|---|---|---|
Basic Auth |
Authorization: Basic [BASE64_KEY_SECRET] |
Used solely on the /token endpoint to request an access token. |
Bearer Token |
Authorization: Bearer [TOKEN] |
Used on all other resource endpoints (SMS, OTP, Balance, etc.). |
// Step 1: Request Access Token
POST /rest/v1/token HTTP/1.1
Authorization: Basic Base64(API_KEY:SECRET)
// Step 2: Use Access Token for API Requests
POST /rest/v1/sms HTTP/1.1
Authorization: Bearer [TOKEN]
/token
Request Access Token
Generate a temporary JWT access token using your API key credentials. The returned token should be cached and reused for all subsequent API requests until it expires.
Headers Required
| Header | Required | Value |
|---|---|---|
Authorization |
Yes | Basic [BASE64_API_KEY_AND_SECRET] |
Response Fields
| Field | Format | Description |
|---|---|---|
token |
string | The generated JWT access token to use for Bearer authentication. |
expiry |
string | Token expiry timestamp in RFC3339 format (Y-m-d\TH:i:sP). |
responseCode |
integer | Response code. 0 indicating success. |
responseMessage |
string | Response message from the server. |
curl -X POST https://api.geniq.io/rest/v1/token \
-H 'Authorization: Basic YW55LWtleTpzZWNyZXQ='`
const axios = require('axios');
const key = 'YOUR_API_KEY';
const secret = 'YOUR_API_SECRET';
const basicAuth = Buffer.from(`${key}:${secret}`).toString('base64');
axios.post('https://api.geniq.io/rest/v1/token', {}, {
headers: { 'Authorization': `Basic ${basicAuth}` }
})
.then(res => console.log(res.data));
import requests
key = "YOUR_API_KEY"
secret = "YOUR_API_SECRET"
response = requests.post(
'https://api.geniq.io/rest/v1/token',
auth=(key, secret)
)
print(response.json())
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://api.geniq.io/rest/v1/token", nil)
req.SetBasicAuth("YOUR_API_KEY", "YOUR_SECRET")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"expiry": "2024-12-11T16:14:46+08:00",
"responseMessage": "Success",
"responseCode": "0",
"token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature"
}
/sms
Send SMS Message
Submit request parameters to queue a text message for sending to a single recipient mobile number.
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
recipient |
integer | Yes | Recipient's mobile number including country code without "+" prefix (e.g. 6591234567). |
originator |
string | Yes | The originator address/Sender ID for the outgoing SMS (e.g. GENIQ). Alphanumeric max 11 characters. |
message |
string | Yes | Body of the SMS message. Supports UTF-8. 160 characters equals 1 SMS segment. |
reference |
string | No | A unique reference ID to track requests and match responses/callbacks. |
originatorTon |
string | No | Type of number (TON): auto (default), national, alpha, international. |
udh |
string | No | User Data Header (hex-encoded string) for binary or concatenated SMS. |
dataCoding |
string | No | Data coding option: auto (default), text (GSM 03.38), or unicode. |
validity |
integer | No | Relative validity time in seconds. Discarded if not delivered within this window. |
Response Fields
| Field | Format | Description |
|---|---|---|
reference |
string | The unique reference submitted in the request, or empty. |
responseCode |
integer | Status code from the API. 0 indicating success. |
responseMessage |
string | Description message corresponding to the response code. |
messageIds |
array | List of unique UUID string message IDs generated for each segment of the sent SMS. |
curl -X POST https://api.geniq.io/rest/v1/sms \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d "recipient=6591234567" \
-d "originator=Hello" \
-d "message=Test message from GENIQ" \
-d "reference=12345"
const axios = require('axios');
const qs = require('qs');
axios.post('https://api.geniq.io/rest/v1/sms', qs.stringify({
recipient: '6591234567',
originator: 'Hello',
message: 'Test message from GENIQ',
reference: '12345'
}), {
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(res => console.log(res.data));
import requests
url = 'https://api.geniq.io/rest/v1/sms'
payload = {
'recipient': '6591234567',
'originator': 'Hello',
'message': 'Test message from GENIQ',
'reference': '12345'
}
headers = {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/x-www-form-urlencoded'
}
response = requests.post(url, data=payload, headers=headers)
print(response.json())
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
)
func main() {
data := url.Values{}
data.Set("recipient", "6591234567")
data.Set("originator", "Hello")
data.Set("message", "Test message from GENIQ")
data.Set("reference", "12345")
req, _ := http.NewRequest("POST", "https://api.geniq.io/rest/v1/sms", strings.NewReader(data.Encode()))
req.Header.Set("Authorization", "Bearer YOUR_TOKEN")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"reference": "12345",
"responseMessage": "Success",
"responseCode": "0",
"messageIds": [
"e36ba3b8-db55-4eef-99e4-79f3e2422846"
]
}
/batch_sms
Send Batch SMS
Submit request parameters to queue a text message for sending to multiple recipient mobile numbers at once. Numbers should be comma-separated.
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
recipients |
string | Yes | Comma-separated list of recipient mobile numbers including country code without "+" prefix (e.g. 6591234567,6581234567). |
originator |
string | Yes | The originator address/Sender ID for the outgoing SMS. Alphanumeric max 11 characters. |
message |
string | Yes | Body of the SMS message. Supports UTF-8. |
reference |
string | No | A unique reference ID to track requests and match responses. |
originatorTon |
string | No | Type of number (TON): auto (default), national, alpha, international. |
udh |
string | No | User Data Header (hex-encoded string) for binary or concatenated SMS. |
dataCoding |
string | No | Data coding option: auto (default), text (GSM 03.38), or unicode. |
validity |
integer | No | Relative validity time in seconds. Discarded if not delivered within this window. |
Response Fields
| Field | Format | Description |
|---|---|---|
reference |
string | The unique reference submitted in the request, or empty. |
responseCode |
integer | Status code from the API. 0 indicating success. |
responseMessage |
string | Description message corresponding to the response code. |
details.total |
integer | Total number of recipients in the batch request. |
details.processed |
integer | Total number of processed recipients. |
details.failed |
integer | Total number of failed recipients. |
details.recipients[] |
array | Array list containing recipient status blocks: recipient, messageIdList, responseCode, and responseMessage. |
curl -X POST https://api.geniq.io/rest/v1/batch_sms \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d "recipients=6591234567,6581234567" \
-d "originator=Hello" \
-d "message=Test batch message from GENIQ" \
-d "reference=12345"
const axios = require('axios');
const qs = require('qs');
axios.post('https://api.geniq.io/rest/v1/batch_sms', qs.stringify({
recipients: '6591234567,6581234567',
originator: 'Hello',
message: 'Test batch message from GENIQ',
reference: '12345'
}), {
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(res => console.log(res.data));
import requests
url = 'https://api.geniq.io/rest/v1/batch_sms'
payload = {
'recipients': '6591234567,6581234567',
'originator': 'Hello',
'message': 'Test batch message from GENIQ',
'reference': '12345'
}
headers = {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/x-www-form-urlencoded'
}
response = requests.post(url, data=payload, headers=headers)
print(response.json())
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
)
func main() {
data := url.Values{}
data.Set("recipients", "6591234567,6581234567")
data.Set("originator", "Hello")
data.Set("message", "Test batch message from GENIQ")
data.Set("reference", "12345")
req, _ := http.NewRequest("POST", "https://api.geniq.io/rest/v1/batch_sms", strings.NewReader(data.Encode()))
req.Header.Set("Authorization", "Bearer YOUR_TOKEN")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"responseMessage": "Success",
"responseCode": "0",
"reference": "12345",
"details": {
"total": 2,
"processed": 2,
"failed": 0,
"recipients": [
{
"recipient": "6591234567",
"messageIdList": ["d6c5e5b9-847b-488a-bd93-c944ee26fafb"],
"responseCode": "0",
"responseMessage": "Success"
},
{
"recipient": "6581234567",
"messageIdList": ["a4c0bce2-0553-44c8-afde-8dada71e5e94"],
"responseCode": "0",
"responseMessage": "Success"
}
]
}
}
/balance
Check Account Balance
Query your current prepaid or postpaid balance amount and associated currency.
Response Fields
| Field | Format | Description |
|---|---|---|
currency |
string | Currency code in ISO 4217 format (e.g. EUR, SGD). |
type |
string | Account billing scheme: Prepaid or Postpaid. |
balance |
decimal | Remaining financial balance amount. |
responseCode |
integer | Status code from the API. 0 indicating success. |
responseMessage |
string | Description message corresponding to the response code. |
curl https://api.geniq.io/rest/v1/balance \
-H 'Authorization: Bearer YOUR_TOKEN'
const axios = require('axios');
axios.get('https://api.geniq.io/rest/v1/balance', {
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
})
.then(res => console.log(res.data));
import requests
response = requests.get(
'https://api.geniq.io/rest/v1/balance',
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
print(response.json())
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.geniq.io/rest/v1/balance", nil)
req.Header.Set("Authorization", "Bearer YOUR_TOKEN")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"currency": "EUR",
"type": "Prepaid",
"responseCode": "0",
"balance": 19.2594,
"responseMessage": "Success"
}
/verify
Send OTP SMS
Generate a One-Time Pin (OTP) code based on RFC6238 and transmit it directly to the recipient's mobile number via optimized SMS routes. An additional fee of €0.005 is charged per successful generation request.
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
recipient |
integer | Yes | Recipient's mobile number including country code without "+" prefix (e.g. 6591234567). |
originator |
string | Yes | The originating address/Sender ID for the OTP SMS message. |
reference |
string | No | A unique reference ID to track requests and responses. |
template |
string | No | The template of the message body. Include the placeholder [CODE] for the actual generated OTP pin (e.g. "Your code is [CODE]."). |
codeLength |
integer | No | The number of digits in the verification code (between 6 and 8). Default is 6. |
expiry |
integer | No | The verification code session validity time in seconds. Default is 30. |
Response Fields
| Field | Format | Description |
|---|---|---|
reference |
string | The unique reference submitted in the request, if any. |
responseCode |
integer | Status code from the API. 0 indicating success. |
responseMessage |
string | Description message corresponding to the response code. |
messageIds |
array | List containing the unique message ID string generated for the OTP SMS. |
curl -X POST https://api.geniq.io/rest/v1/verify \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d "recipient=6591234567" \
-d "originator=Hello" \
-d "reference=12345" \
-d "expiry=300"
const axios = require('axios');
const qs = require('qs');
axios.post('https://api.geniq.io/rest/v1/verify', qs.stringify({
recipient: '6591234567',
originator: 'Hello',
reference: '12345',
expiry: 300
}), {
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(res => console.log(res.data));
import requests
url = 'https://api.geniq.io/rest/v1/verify'
payload = {
'recipient': '6591234567',
'originator': 'Hello',
'reference': '12345',
'expiry': 300
}
headers = {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/x-www-form-urlencoded'
}
response = requests.post(url, data=payload, headers=headers)
print(response.json())
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
)
func main() {
data := url.Values{}
data.Set("recipient", "6591234567")
data.Set("originator", "Hello")
data.Set("reference", "12345")
data.Set("expiry", "300")
req, _ := http.NewRequest("POST", "https://api.geniq.io/rest/v1/verify", strings.NewReader(data.Encode()))
req.Header.Set("Authorization", "Bearer YOUR_TOKEN")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"reference": "12345",
"responseMessage": "Success",
"responseCode": "0",
"messageIds": [
"62bf1beb-9451-40b5-9171-6f45f8935111"
]
}
/verify/{messageId}
Verifying OTP SMS
Submit the verification code received by the recipient along with the unique messageId previously returned during OTP generation.
Path / Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
messageId |
string | Yes (Path) | A unique ID that was previously returned by our API when sending out the OTP SMS. |
code |
string | Yes (Query) | The verification OTP code input to verify. |
Request Parameters (Body)
| Field | Type | Required | Description |
|---|---|---|---|
reference |
string | No | A unique reference ID to match requests and responses. |
Response Fields
| Field | Format | Description |
|---|---|---|
reference |
string | The unique reference submitted in the request, if any. |
responseCode |
integer | Status code from the API. 0 indicating success. |
responseMessage |
string | Description message corresponding to the response code. |
curl -X POST "https://api.geniq.io/rest/v1/verify/otp_session_id?code=123456" \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d "reference=12345"
const axios = require('axios');
const qs = require('qs');
axios.post('https://api.geniq.io/rest/v1/verify/otp_session_id?code=123456', qs.stringify({
reference: '12345'
}), {
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(res => console.log(res.data));
import requests
url = 'https://api.geniq.io/rest/v1/verify/otp_session_id?code=123456'
payload = {
'reference': '12345'
}
headers = {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/x-www-form-urlencoded'
}
response = requests.post(url, data=payload, headers=headers)
print(response.json())
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
)
func main() {
data := url.Values{}
data.Set("reference", "12345")
req, _ := http.NewRequest(
"POST",
"https://api.geniq.io/rest/v1/verify/otp_session_id?code=123456",
strings.NewReader(data.Encode()),
)
req.Header.Set("Authorization", "Bearer YOUR_TOKEN")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"reference": "12345",
"responseMessage": "Success",
"responseCode": "0"
}
/whatsapp/messages
Send WhatsApp Message
Deliver interactive, rich media, and template-based WhatsApp messages. Select a message type below to see its description, parameter table, and cURL payload example.
Note: Every WhatsApp message request requires recipient (country code + phone number without +) and type.
Send a standard text message. Text messages support formatting (e.g. *bold*, _italic_, ~strikethrough~).
| Field | Type | Required | Description |
|---|---|---|---|
recipient | integer | Yes | Recipient's mobile number (e.g., 6591234567). |
type | string | Yes | Set to "text". |
body | string | Yes | The body of the message. |
previewUrl | boolean | No | Generate link preview for URLs. Default: false. |
smsFallback | boolean | No | Fallback to SMS if delivery fails. Default: false. |
reference | string | No | Custom tracking reference ID. |
Send an image message. Supported formats are JPEG and PNG. Maximum image size is 5 MB.
| Field | Type | Required | Description |
|---|---|---|---|
recipient | integer | Yes | Recipient's mobile number. |
type | string | Yes | Set to "image". |
url | string | Yes | Publicly accessible URL of the image. |
caption | string | No | Caption text for the image. |
smsFallback | boolean | No | Fallback to SMS on failure. Default: false. |
reference | string | No | Custom tracking reference ID. |
Send a video message. Supported formats are MP4 and 3GP. Maximum video size is 15 MB.
| Field | Type | Required | Description |
|---|---|---|---|
recipient | integer | Yes | Recipient's mobile number. |
type | string | Yes | Set to "video". |
url | string | Yes | Publicly accessible URL of the video. |
caption | string | No | Caption text for the video. |
smsFallback | boolean | No | Fallback to SMS on failure. Default: false. |
reference | string | No | Custom tracking reference ID. |
Send an audio message or voice note. Supported formats include MP3, OGA, and M4A.
| Field | Type | Required | Description |
|---|---|---|---|
recipient | integer | Yes | Recipient's mobile number. |
type | string | Yes | Set to "audio". |
url | string | Yes | Publicly accessible URL of the audio file. |
smsFallback | boolean | No | Fallback to SMS on failure. Default: false. |
reference | string | No | Custom tracking reference ID. |
Send a sticker message. Supported format is WEBP. Maximum file size is 100 KB.
| Field | Type | Required | Description |
|---|---|---|---|
recipient | integer | Yes | Recipient's mobile number. |
type | string | Yes | Set to "sticker". |
url | string | Yes | Publicly accessible URL of the WEBP sticker. |
caption | string | No | Sticker caption. |
reference | string | No | Custom tracking reference ID. |
Send document files such as PDFs or Word documents. Maximum document size is 100 MB.
| Field | Type | Required | Description |
|---|---|---|---|
recipient | integer | Yes | Recipient's mobile number. |
type | string | Yes | Set to "document". |
url | string | Yes | Publicly accessible URL of the document file. |
filename | string | Yes | Filename with extension (e.g., "invoice.pdf"). |
caption | string | No | Caption/description. |
smsFallback | boolean | No | Fallback to SMS on failure. Default: false. |
reference | string | No | Custom tracking reference ID. |
Send geographical coordinates with location pin details.
| Field | Type | Required | Description |
|---|---|---|---|
recipient | integer | Yes | Recipient's mobile number. |
type | string | Yes | Set to "location". |
latitude | float | Yes | Latitude coordinate (e.g., 55.7047). |
longitude | float | Yes | Longitude coordinate (e.g., 13.191). |
locationName | string | Yes | Label or name of the location. |
address | string | Yes | Postal address string. |
reference | string | No | Custom tracking reference ID. |
Send pre-approved WhatsApp Templates. Templates support custom body/header parameters and OTP flows.
| Field | Type | Required | Description |
|---|---|---|---|
recipient | integer | Yes | Recipient's mobile number. |
type | string | Yes | Set to "template". |
name | string | Yes | Approved template name. |
language | string | Yes | Language code (e.g., "en"). |
headerParams | array | No | Array of strings replacing {{1}} in headers. |
bodyParams | array | No | Array of strings replacing body placeholders {{1}}, {{2}}. |
otp | string | No | Authentication template code to fill the OTP variables. |
reference | string | No | Custom tracking reference ID. |
curl -X POST https://api.geniq.io/rest/v1/whatsapp/messages \
-H 'Authorization: Bearer [TOKEN]' \
-H 'Content-Type: application/json' \
-d '{
"recipient": "6591234567",
"type": "text",
"body": "Hello, this is a *bold* test message from GENIQ!",
"reference": "ref123"
}'
const axios = require('axios');
axios.post('https://api.geniq.io/rest/v1/whatsapp/messages', {
recipient: "6591234567",
type: "text",
body: "Hello, this is a *bold* test message from GENIQ!",
reference: "ref123"
}, {
headers: { 'Authorization': 'Bearer [TOKEN]' }
}).then(res => console.log(res.data));
import requests
headers = { 'Authorization': 'Bearer [TOKEN]' }
data = {
"recipient": "6591234567",
"type": "text",
"body": "Hello, this is a *bold* test message from GENIQ!",
"reference": "ref123"
}
response = requests.post('https://api.geniq.io/rest/v1/whatsapp/messages', json=data, headers=headers)
print(response.json())
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func main() {
payload := map[string]interface{}{
"recipient": "6591234567",
"type": "text",
"body": "Hello, this is a *bold* test message from GENIQ!",
"reference": "ref123",
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.geniq.io/rest/v1/whatsapp/messages", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer [TOKEN]")
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
curl -X POST https://api.geniq.io/rest/v1/whatsapp/messages \
-H 'Authorization: Bearer [TOKEN]' \
-H 'Content-Type: application/json' \
-d '{
"recipient": "6591234567",
"type": "image",
"url": "https://geniq.io/media/sample.jpg",
"caption": "Sample Image Caption",
"reference": "12345"
}'
const axios = require('axios');
axios.post('https://api.geniq.io/rest/v1/whatsapp/messages', {
recipient: "6591234567",
type: "image",
url: "https://geniq.io/media/sample.jpg",
caption: "Sample Image Caption",
reference: "12345"
}, {
headers: { 'Authorization': 'Bearer [TOKEN]' }
}).then(res => console.log(res.data));
import requests
headers = { 'Authorization': 'Bearer [TOKEN]' }
data = {
"recipient": "6591234567",
"type": "image",
"url": "https://geniq.io/media/sample.jpg",
"caption": "Sample Image Caption",
"reference": "12345"
}
response = requests.post('https://api.geniq.io/rest/v1/whatsapp/messages', json=data, headers=headers)
print(response.json())
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func main() {
payload := map[string]interface{}{
"recipient": "6591234567",
"type": "image",
"url": "https://geniq.io/media/sample.jpg",
"caption": "Sample Image Caption",
"reference": "12345",
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.geniq.io/rest/v1/whatsapp/messages", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer [TOKEN]")
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
curl -X POST https://api.geniq.io/rest/v1/whatsapp/messages \
-H 'Authorization: Bearer [TOKEN]' \
-H 'Content-Type: application/json' \
-d '{
"recipient": "6591234567",
"type": "video",
"url": "https://geniq.io/media/sample.mp4",
"caption": "Sample Video Caption",
"reference": "12345"
}'
const axios = require('axios');
axios.post('https://api.geniq.io/rest/v1/whatsapp/messages', {
recipient: "6591234567",
type: "video",
url: "https://geniq.io/media/sample.mp4",
caption: "Sample Video Caption",
reference: "12345"
}, {
headers: { 'Authorization': 'Bearer [TOKEN]' }
}).then(res => console.log(res.data));
import requests
headers = { 'Authorization': 'Bearer [TOKEN]' }
data = {
"recipient": "6591234567",
"type": "video",
"url": "https://geniq.io/media/sample.mp4",
"caption": "Sample Video Caption",
"reference": "12345"
}
response = requests.post('https://api.geniq.io/rest/v1/whatsapp/messages', json=data, headers=headers)
print(response.json())
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func main() {
payload := map[string]interface{}{
"recipient": "6591234567",
"type": "video",
"url": "https://geniq.io/media/sample.mp4",
"caption": "Sample Video Caption",
"reference": "12345",
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.geniq.io/rest/v1/whatsapp/messages", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer [TOKEN]")
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
curl -X POST https://api.geniq.io/rest/v1/whatsapp/messages \
-H 'Authorization: Bearer [TOKEN]' \
-H 'Content-Type: application/json' \
-d '{
"recipient": "6591234567",
"type": "audio",
"url": "https://geniq.io/media/sample.mp3",
"reference": "12345"
}'
const axios = require('axios');
axios.post('https://api.geniq.io/rest/v1/whatsapp/messages', {
recipient: "6591234567",
type: "audio",
url: "https://geniq.io/media/sample.mp3",
reference: "12345"
}, {
headers: { 'Authorization': 'Bearer [TOKEN]' }
}).then(res => console.log(res.data));
import requests
headers = { 'Authorization': 'Bearer [TOKEN]' }
data = {
"recipient": "6591234567",
"type": "audio",
"url": "https://geniq.io/media/sample.mp3",
"reference": "12345"
}
response = requests.post('https://api.geniq.io/rest/v1/whatsapp/messages', json=data, headers=headers)
print(response.json())
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func main() {
payload := map[string]interface{}{
"recipient": "6591234567",
"type": "audio",
"url": "https://geniq.io/media/sample.mp3",
"reference": "12345",
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.geniq.io/rest/v1/whatsapp/messages", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer [TOKEN]")
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
curl -X POST https://api.geniq.io/rest/v1/whatsapp/messages \
-H 'Authorization: Bearer [TOKEN]' \
-H 'Content-Type: application/json' \
-d '{
"recipient": "6591234567",
"type": "sticker",
"url": "https://geniq.io/media/sample.webp",
"caption": "Sample Sticker",
"reference": "12345"
}'
const axios = require('axios');
axios.post('https://api.geniq.io/rest/v1/whatsapp/messages', {
recipient: "6591234567",
type: "sticker",
url: "https://geniq.io/media/sample.webp",
caption: "Sample Sticker",
reference: "12345"
}, {
headers: { 'Authorization': 'Bearer [TOKEN]' }
}).then(res => console.log(res.data));
import requests
headers = { 'Authorization': 'Bearer [TOKEN]' }
data = {
"recipient": "6591234567",
"type": "sticker",
"url": "https://geniq.io/media/sample.webp",
"caption": "Sample Sticker",
"reference": "12345"
}
response = requests.post('https://api.geniq.io/rest/v1/whatsapp/messages', json=data, headers=headers)
print(response.json())
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func main() {
payload := map[string]interface{}{
"recipient": "6591234567",
"type": "sticker",
"url": "https://geniq.io/media/sample.webp",
"caption": "Sample Sticker",
"reference": "12345",
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.geniq.io/rest/v1/whatsapp/messages", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer [TOKEN]")
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
Manage WhatsApp Templates
Create, retrieve, or delete pre-approved message templates. WhatsApp requires templates for business-initiated communication outside of active 24-hour conversation sessions.
Create Template
/whatsapp/message_templates
Submit a new template design for pre-approval. Authentication categories must be configured properly.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique identifier name (e.g. "auth_sample"). |
language | string | Yes | Supported language code (e.g. "en"). |
category | string | Yes | "MARKETING", "UTILITY", or "AUTHENTICATION". |
header | string | No | Header text context. Supports 1 variable placeholder (e.g., "Hi {{1}}"). |
headerFormat | string | No | Currently supports "text". |
headerExample | array | No | String examples matching the header variables. |
body | string | Yes | Main template text content. Supports variables like {{1}}, {{2}}. |
bodyExample | array | No | String examples matching the body variables. |
footer | string | No | Footer signature text. Static content only (no variables). |
otpAddSecurityRecommendation | boolean | No | For Authentication: Appends Meta security advice. Default: false. |
otpMessageTtl | string | No | For Authentication: TTL in minutes (between 30s and 90m). |
otpExpiredAfter | string | No | For Authentication: TTL display context in minutes. |
otpCopyButtonText | string | No | For Authentication: Label for copy button (max 25 chars). |
Retrieve Templates
/whatsapp/message_templates
Get a list of templates filtered by limit, status, category, or language.
| Query Param | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Result count limit per page. |
category | string | No | Filter by "UTILITY", "AUTHENTICATION", "MARKETING". |
status | string | No | Filter by "APPROVED", "PENDING", "REJECTED", "DISABLED", etc. |
name | string | No | Exact name match filter. |
language | string | No | Language code filter. |
Delete Template
/whatsapp/message_templates
Delete a pre-existing template. Deletions are irreversible.
| Query Param | Type | Required | Description |
|---|---|---|---|
name | string | Yes | The template name identifier to delete. |
id | string | No | The direct template ID. |
curl -X POST https://api.geniq.io/rest/v1/whatsapp/message_templates \
-H 'Authorization: Bearer [TOKEN]' \
-H 'Content-Type: application/json' \
-d '{
"name": "sample_template",
"language": "en",
"category": "MARKETING",
"header": "Welcome {{1}}",
"headerFormat": "text",
"headerExample": ["User"],
"body": "Nice to meet you. Welcome to GENIQ {{1}}!",
"bodyExample": ["Ali"],
"footer": "Thanks"
}'
curl -X GET "https://api.geniq.io/rest/v1/whatsapp/message_templates\
?limit=5&category=MARKETING" \
-H 'Authorization: Bearer [TOKEN]'
curl -X DELETE "https://api.geniq.io/rest/v1/whatsapp/message_templates\
?name=sample_template" \
-H 'Authorization: Bearer [TOKEN]'
/voice
Text-to-Speech Callout
Convert written text into automated voice calls. The Voice API rings the recipient and speaks the message in the language/locale of choice.
| Field | Type | Required | Description |
|---|---|---|---|
recipient | string | Yes | Recipient's mobile number (e.g. "6591234567"). |
message | string | Yes | Text context to convert into voice speech. |
locale | string | Yes | Voice language engine locale code (e.g., "en-US"). |
originator | string | Yes | The Caller ID to display (default: "6531596518"). |
reference | string | No | Custom tracking reference ID. |
curl -X POST https://api.geniq.io/rest/v1/voice \
-H 'Authorization: Bearer [TOKEN]' \
-H 'Content-Type: application/json' \
-d '{
"recipient": "6591234567",
"message": "Hi, this is a test text-to-speech callout from GENIQ. Your verification code is 5 5 2 1.",
"locale": "en-US",
"originator": "6531596518",
"reference": "call_123"
}'
const axios = require('axios');
axios.post('https://api.geniq.io/rest/v1/voice', {
recipient: "6591234567",
message: "Hi, this is a test text-to-speech callout from GENIQ. Your verification code is 5 5 2 1.",
locale: "en-US",
originator: "6531596518",
reference: "call_123"
}, {
headers: { 'Authorization': 'Bearer [TOKEN]' }
}).then(res => console.log(res.data));
import requests
headers = { 'Authorization': 'Bearer [TOKEN]' }
data = {
"recipient": "6591234567",
"message": "Hi, this is a test text-to-speech callout from GENIQ. Your verification code is 5 5 2 1.",
"locale": "en-US",
"originator": "6531596518",
"reference": "call_123"
}
response = requests.post('https://api.geniq.io/rest/v1/voice', json=data, headers=headers)
print(response.json())
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func main() {
payload := map[string]interface{}{
"recipient": "6591234567",
"message": "Hi, this is a test text-to-speech callout from GENIQ. Your verification code is 5 5 2 1.",
"locale": "en-US",
"originator": "6531596518",
"reference": "call_123",
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.geniq.io/rest/v1/voice", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer [TOKEN]")
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
/voice
Custom IVR Callout
Create dynamic, multi-tier interactive voice response (IVR) phone surveys or routing lines using nested DTMF menus.
| Field | Type | Required | Description |
|---|---|---|---|
recipient | string | Yes | Recipient's mobile number. |
originator | string | Yes | Caller ID display number. |
locale | string | Yes | TTS voice engine locale. |
maxDuration | integer | No | Maximum call duration in seconds. |
barge | boolean | No | Allow DTMF buttons to interrupt/skip active spoken message. Default: false. |
menus | array | Yes | Nested list of menu objects. |
menus[].menuId | string | Yes | Unique identifier name for this menu node. |
menus[].message | string | Yes | The spoken prompt message for this menu. |
menus[].options | array | Yes | Digit options array. See below. |
options[].dtmf | string | Yes | Digit key pressed (e.g. "1", "2"). |
options[].action | string | Yes | "return" (ends call and records DTMF value) or "menus" (navigates). |
options[].returnValue | string | No | Value to return on "return" action (single word). |
options[].targetMenu | string | No | Target menu identifier if action is "menus". |
curl -X POST https://api.geniq.io/rest/v1/voice \
-H 'Authorization: Bearer [TOKEN]' \
-H 'Content-Type: application/json' \
-d '{
"recipient": "6591234567",
"originator": "6531596518",
"reference": "survey_1",
"maxDuration": 30,
"barge": true,
"locale": "en-US",
"menus": [
{
"menuId": "main",
"message": "Press 1 for Support, or press 2 to speak to Sales.",
"options": [
{ "dtmf": "1", "action": "return", "returnValue": "Support" },
{ "dtmf": "2", "action": "return", "returnValue": "Sales" }
]
}
]
}'
curl -X POST https://api.geniq.io/rest/v1/voice \
-H 'Authorization: Bearer [TOKEN]' \
-H 'Content-Type: application/json' \
-d '{
"recipient": "6591234567",
"originator": "6531596518",
"reference": "nest_1",
"maxDuration": 45,
"barge": true,
"locale": "en-US",
"menus": [
{
"menuId": "main",
"message": "Press 1 for Billing, or press 2 for general support menu.",
"options": [
{ "dtmf": "1", "action": "return", "returnValue": "Billing" },
{ "dtmf": "2", "action": "menus", "targetMenu": "sub_support" }
]
},
{
"menuId": "sub_support",
"message": "Press 1 for technical help, or press 2 to return to main menu.",
"options": [
{ "dtmf": "1", "action": "return", "returnValue": "TechHelp" },
{ "dtmf": "2", "action": "menus", "targetMenu": "main" }
]
}
]
}'
Supported Voice Locales
Below is the listing of supported voices, languages, and locale identifiers for text-to-speech calls.
| Language | Locale Code |
|---|---|
| English (US) | en-US |
| English (British) | en-GB |
| English (Australian) | en-AU |
| English (Indian) | en-IN |
| Chinese Mandarin | cmn-CN |
| Chinese Cantonese | zh-HK |
| Malay (Malaysia) | ms-MY |
| Indonesian | id-ID |
| Arabic | arb |
| Spanish | es-ES |
| Spanish (US) | es-US |
| Portuguese (European) | pt-PT |
| Portuguese (Brazilian) | pt-BR |
| French | fr-FR |
| French (Canadian) | fr-CA |
| German | de-DE |
| Italian | it-IT |
| Japanese | ja-JP |
| Korean | ko-KR |
| Turkish | tr-TR |
| Russian | ru-RU |
| Polish | pl-PL |
| Thai | th-TH |
| Vietnamese | vi-VN |
// Set the "locale" variable inside voice JSON
{
"recipient": "6591234567",
"message": "Welcome to GENIQ Technologies",
"locale": "en-US" // or cmn-CN, ms-MY, etc.
}
Receiving SMS Callback
Incoming SMS messages sent to your virtual numbers are forwarded to your configured webhook URL via an HTTP POST request. The application server should return a status code of 200 OK; otherwise, the gateway will retry transmission.
| Field | Type | Description |
|---|---|---|
messageId |
string | A unique ID associated with this received SMS message. |
recipient |
integer | The recipient of this SMS message (your virtual number/short code). |
originator |
integer | The sender of this message (mobile handset number). |
udh |
string | User Data Header. Only present if the incoming message is concatenated. |
message |
string | The body content of the incoming SMS message. |
messageTimestamp |
string | The creation date and time of the message in RFC3339 format (Y-m-d\TH:i:sP). |
POST /your_webhook_endpoint HTTP/1.1
Host: your_domain.com
Content-Type: application/x-www-form-urlencoded
messageId=msg123\
&recipient=88888\
&originator=6591234567\
&message=hello\
&messageTimestamp=2017-01-03T14%3A31%3A28%2B08%3A00
SMS Delivery Reports
Real-time SMS delivery status updates are forwarded to your configured callback webhook via HTTP POST. If your server is offline or fails to respond with a 200 OK status, the gateway will queue the DLR for retry.
| Field | Type | Description |
|---|---|---|
messageId |
string | The unique ID that was previously returned by our API when sending out the SMS. |
channel |
string | The channel type. For SMS, this value will always be set to "sms". |
recipient |
integer | The recipient's mobile number. |
status |
string | The status of the message sent. Possible values: processed, delivered, expired, deleted, undeliverable, rejected, unknown. |
reasonCode |
integer | Additional error description code if transmission fails. Refer to the Reason Codes reference table. |
messageTimestamp |
string | The creation date and time of this report on GENIQ in RFC3339 format. |
operatorTimestamp |
string | The creation date and time of this report on the operator SMSC in RFC3339 format. |
POST /your_webhook_endpoint HTTP/1.1
Host: your_domain.com
Content-Type: application/x-www-form-urlencoded
messageId=msg123\
&channel=sms\
&recipient=6591234567\
&status=delivered\
&reasonCode=0\
&messageTimestamp=2017-01-03T14%3A31%3A28%2B08%3A00\
&operatorTimestamp=2017-01-03T14%3A31%3A00%2B08%3A00
Receiving WhatsApp Callback
Incoming WhatsApp messages will be delivered to a pre-configured callback URL using the HTTP POST method with a JSON body payload.
| Field | Type | Description |
|---|---|---|
messageId | string | A unique ID associated with this WhatsApp message. |
type | string | Message type. Possible values: text, image, video, audio, document, location, sticker, contact. |
recipient | integer | The business number receiving the message. |
originator | integer | The sender's mobile number. |
originatorName | string | The sender's profile display name. |
body | string | Message body text. Only present for type "text". |
url | string | Publicly accessible URL of the media file (image, video, audio, sticker, document). |
messageTimestamp | string | The message creation timestamp in RFC3339 format (Y-m-d\TH:i:sP). |
{
"messageId": "a662179e-ba00-492f-a0b7-06b3fa002502",
"type": "text",
"originator": "6588880000",
"originatorName": "Mark Gold",
"recipient": "6598989898",
"body": "Hi, this is a test message",
"messageTimestamp": "2025-02-20T14:45:42+08:00"
}
{
"messageId": "45fd72c3-3495-4313-ba5d-be2d0acff3ca",
"type": "image",
"originator": "6588880000",
"originatorName": "Mark Gold",
"recipient": "6598989898",
"url": "https://geniq.io/media/callback.jpg",
"messageTimestamp": "2025-02-20T14:57:43+08:00"
}
WhatsApp Delivery Reports
Delivery status updates for sent WhatsApp messages are forwarded to your webhook URL via HTTP POST JSON payloads.
| Field | Type | Description |
|---|---|---|
messageId | string | The unique message ID returned by the API during submission. |
channel | string | Will always be set to "whatsapp". |
recipient | integer | The mobile number of the recipient. |
status | string | Status: processed, sent, delivered, read, failed, expired, exceeded_retry. |
reasonCode | integer | Standardized reason failure code. 0 indicating success. |
messageTimestamp | string | GENIQ platform event creation timestamp (RFC3339). |
providerTimestamp | string | Meta platform event creation timestamp (RFC3339). |
đź’ˇ Webhook Response
Your server should always respond with HTTP Status Code 200 (OK). Any other status will trigger automatic delivery retries.
{
"messageId": "0c5b63cf-b41e-449c-a077-9124de0b87dc",
"recipient": "6588880000",
"status": "delivered",
"reasonCode": "0",
"channel": "whatsapp",
"messageTimestamp": "2025-02-20T15:23:56+08:00",
"providerTimestamp": "2025-02-20T15:23:55+08:00"
}
SMPP Protocol Reference
GENIQ operates a high-throughput, low-latency Short Message Peer-to-Peer (SMPP) gateway for customers needing native telecommunication interfaces. Our gateway fully supports the SMPP v3.4 standard exclusively.
Contact our integration sales team to request SMPP system credentials and whitelist client IP ranges.
Connection Parameters
| Parameter | Value / Description |
|---|---|
Host |
smpp.geniq.io |
Port |
2775 |
system_id |
Your assigned client system ID. |
password |
Your assigned client password credentials. |
system_type |
Ignored. |
Binds & Throughput
| Property | Default Limit |
|---|---|
Binds per system_id |
2 (transceiver, transmitter, or receiver binds) |
Maximum Throughput |
10 messages per second (can be raised upon request) |
Supported PDUs
| PDU Name | Command ID | Type |
|---|---|---|
bind_receiver / bind_receiver_resp |
0x00000001 / 0x80000001 |
Session management |
bind_transmitter / bind_transmitter_resp |
0x00000002 / 0x80000002 |
Session management |
bind_transceiver / bind_transceiver_resp |
0x00000009 / 0x80000009 |
Session management |
submit_sm / submit_sm_resp |
0x00000004 / 0x80000004 |
Message submission |
deliver_sm / deliver_sm_resp |
0x00000005 / 0x80000005 |
Delivery report / Mobile terminated receive |
unbind / unbind_resp |
0x00000006 / 0x80000006 |
Session termination |
enquire_link / enquire_link_resp |
0x00000015 / 0x80000015 |
Keep-alive signal |
generic_nack |
0x80000000 |
Negative response packet |
Supported Data Codings
| Value | Encoding / Alphabet Scheme |
|---|---|
0 |
GSM7 default alphabet |
1 |
GSM7 default alphabet |
2 |
8-Bit binary encoding data |
8 |
UTF-16BE (UCS2) double-byte alphabet |
Concatenated SMS TLVs
| Tag Name | Hex Value | Description |
|---|---|---|
sar_msg_ref_num |
0x020C |
Concatenation message reference number index. |
sar_total_segments |
0x020E |
Total parts number count in multipart text. |
sar_segment_seqnum |
0x020F |
The current part index segment sequence number. |
// SMPP v3.4 binds can be initiated via TCP socket to smpp.geniq.io:2775.
// IP authentication is required prior to binding.
// Ensure transmitter or transceiver bind requests contain system_id and password.
// Periodic enquire_link PDUs must be sent every 30 seconds to avoid connection drop.
API Response & Reason Codes
GENIQ maps all API requests to standard HTTP status codes, complemented by descriptive custom application codes in the JSON body payloads.
RESTful API Response Codes
| Code | Description / Meaning |
|---|---|
0 | Success |
1 | Invalid Username or Password |
2 | Invalid IP request |
3 | Account has expired |
4 | Account is disabled |
5 | Account maximum throttling rate is exceeded |
6 | Account does not have sufficient credit balance |
7 | Prepaid Account has expired |
10 | Could not route message |
11 | Invalid recipient address |
12 | Invalid originating address |
13 | Invalid alphanumeric originating address |
14 | Could not route message due to account limitations |
15 | Subscriber has blocked this service |
16 | Destination Address Duplicated |
17 | Destination Address list exceeded maximum |
18 | API token generation failed |
19 | Spam Control threshold exceeded |
20 | Invalid Token |
21 | Invalid messageId |
22 | Invalid code |
23 | Token expired |
24 | Invalid API Key credentials |
88 | General Failure |
99 | System error. Please contact us if problem persists |
SMS Delivery Reason Codes
Reason codes returned inside delivery reports when an SMS fails to transmit to the destination handset.
| Code | Description / Failure Cause |
|---|---|
0 | Not Applicable / Success |
1 | Base Station Unknown |
2 | MSC Unknown |
3 | Format Error |
4 | Other Error |
5 | Subscriber Unknown |
6 | Subscriber Barred |
7 | Subscriber Not Provisioned |
8 | Subscriber Absent |
9 | SMSC Failure |
10 | SMSC Congestion |
11 | SMSC Roaming |
12 | Handset Error |
13 | Handset Memory Exceeded |
201 | Invalid WhatsApp Template |
WhatsApp Channel Response Codes
| Code | Description / Meaning |
|---|---|
301 | No valid WhatsApp session found |
302 | WhatsApp Template not found |
303 | WhatsApp Template param type 'otp' is required for the authentication template |
304 | WhatsApp Template is not approved |
305 | WhatsApp Template param count mismatch |
306 | WhatsApp Template param type 'otp' is required for authentication template |
311 | WhatsApp Template rejected |
312 | WhatsApp Template with same content already existed |
313 | WhatsApp Template is missing the name field |
314 | WhatsApp Template is missing the language field |
315 | WhatsApp Template is missing the category field |
316 | WhatsApp Template is missing the body field |
317 | WhatsApp Template is missing the header parameter example |
318 | WhatsApp Template is missing the body parameter example |
319 | WhatsApp Template has an invalid number of body parameter examples |
320 | WhatsApp Template contains an invalid footer. Variables are not supported in the footer |
321 | WhatsApp Template header format must be one of {TEXT, IMAGE} |
322 | WhatsApp Template category must be one of {UTILITY, MARKETING, AUTHENTICATION} |
323 | WhatsApp Template header field can only have up to 1 variable(s) |
324 | WhatsApp Template header has an invalid variable sequence |
325 | WhatsApp Template body has an invalid variable sequence |
326 | WhatsApp Template OTP time to live value must be higher than or equal to 30 |
327 | WhatsApp Template OTP code expiry time should be between 1 and 90 minutes |
328 | WhatsApp Template OTP copy button text can't have more than 25 characters |
{
"responseCode": "6",
"responseMessage": "Account does not have sufficient credit balance"
}