Getting Started
MSGly menyediakan REST API berkecepatan tinggi dengan autentikasi berbasis standar industri OAuth 2.0 (Client Credentials). Pengiriman pesan didukung oleh cluster antrean Redis asinkron dan device pool WhatsApp yang berputar secara dinamis (round-robin).
| Konfigurasi | Nilai Produksi |
|---|---|
| Production Base URL | https://api.msgly.id/api/v1 |
| Otentikasi | OAuth 2.0 (Bearer Token via Client Credentials) |
| Format Data | JSON (Request Body & Response), URL-Encoded (OAuth Token) |
| ID Idempotency | xid (Wajib unik per transaksi pengiriman) |
Alur Persiapan Integrasi
- Login ke Dashboard MSGly: Akses dashboard.msgly.id dengan akun Client Anda.
- Buat API Client: Masuk ke menu API Client di sidebar, lalu klik Create New API Client. Masukkan nama aplikasi dan daftarkan
Webhook URL(opsional) untuk callback status delivery. - Simpan Kredensial: Salin
client_iddanclient_secretAnda. Pastikan menyimpannya di environment variable backend. - Request Access Token: Tukar Client ID & Secret dengan Bearer Token melalui endpoint
POST /api/v1/oauth/token. - Kirim Pesan: Kirim WhatsApp OTP atau pesan tunggal melalui endpoint
POST /api/v1/message.
client_secret pada kode frontend (React, Vue, mobile apps, atau browser scripts). Seluruh interaksi dengan API MSGly wajib dilakukan dari server/backend Anda.
Authentication (OAuth 2.0)
MSGly menggunakan grant type client_credentials. Kredensial client_id dan client_secret ditukarkan dengan Access Token yang berlaku selama 24 jam (86.400 detik).
Mendapatkan access token Bearer untuk otentikasi request berikutnya.
Request Header & Body (application/x-www-form-urlencoded):
| Parameter | Tipe | Wajib | Deskripsi |
|---|---|---|---|
grant_type | string | Wajib | Harus bernilai tepat client_credentials |
client_id | string | Wajib | Client ID yang diterbitkan dari Dashboard MSGly |
client_secret | string | Wajib | Client Secret yang diterbitkan dari Dashboard MSGly |
curl -X POST https://api.msgly.id/api/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET"
{
"success": true,
"message": "token issued",
"data": {
"access_token": "msgly_tk_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 86400
}
}
/oauth/token pada setiap pengiriman pesan agar tidak terkena rate limit.
Kirim Pesan (/message)
Pengiriman pesan WhatsApp API eksternal dikirimkan melalui endpoint terpadu POST /api/v1/message. Layanan yang didukung meliputi WhatsApp OTP, WhatsApp Notification, WhatsApp Reminder (langsung / terjadwal), serta Single Message. Sistem akan otomatis memilih WhatsApp device yang aktif dari pool akun dan meng-enqueue pesan ke dalam antrean Redis dengan prioritas tinggi.
notification, reminder, dan single dapat dikonfigurasi aktif/nonaktif melalui dashboard admin. Pengiriman pesan promosi/broadcast massal tetap dilayani melalui fitur WhatsApp Blast di Dashboard.
Parameter Request (JSON Body):
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
xid |
string | Wajib | ID unik transaksi Anda (Idempotency Key). Menjamin tidak ada pesan ganda terkirim saat terjadi retry jaringan. |
to |
string | Wajib | Nomor WhatsApp tujuan dalam format internasional (contoh: 628123456789). Awalan lokal 08... otomatis dinormalkan sistem ke 628.... |
type |
string | Wajib | Pilihan tipe pesan: otp, notification, reminder, atau single. |
message |
string | Opsional* | Teks pesan bebas langsung (wajib jika tidak menggunakan template pada notifikasi/reminder/single). |
code |
string | Opsional (OTP) | Kode OTP angka/alfanumerik untuk mode rotasi OTP otomatis oleh server. |
template |
object | Opsional* | Objek template spesifik { "template_id": "UUID", "params": ["..."] } bila memilih pengiriman berbasis template berparameter. |
scheduled_at |
string | Opsional (Reminder) | Waktu pengiriman terjadwal dalam format ISO 8601 / RFC3339 (contoh: 2026-09-25T09:00:00Z). Jika kosong atau waktu lampau, pesan dikirim saat itu juga. |
{
"messages": {
"id": "7c4817a5-d85c-48c0-845f-c9ab579899eb",
"xid": "trx-unique-001",
"status": "queued",
"timestamp": 1718451123456
}
}
queued beserta id (MSGly Message UUID) dalam waktu < 50ms. Status delivery lanjutan (sent, delivered, read, failed) dan WhatsApp Message ID (oid) akan dikirimkan secara asinkron melalui Webhook Callback.
WhatsApp OTP
Pengiriman kode verifikasi OTP WhatsApp dirancang dengan latensi minimal dan tingkat pengiriman tinggi. MSGly mendukung dua skenario integrasi:
Skenario A: OTP Template Rotation (Direkomendasikan)
Jika fitur OTP Rotation diaktifkan untuk akun Anda di Dashboard, server MSGly secara dinamis memilih template pesan acak dari template yang telah di-whitelist. Anda cukup mengirimkan nomor tujuan dan kode OTP-nya saja. Cara ini terbukti paling efektif menjaga performa nomor sender dari deteksi spam WhatsApp.
{
"xid": "otp-trx-993",
"to": "628123456789",
"type": "otp",
"code": "482019"
}
Skenario B: Manual Template Selection
Jika Anda perlu menggunakan template tertentu (misalnya template login khusus atau registrasi tertentu), sertakan UUID template_id dan array params.
{
"xid": "otp-trx-992",
"to": "628123456789",
"type": "otp",
"template": {
"template_id": "c8f7a1b2-3c4d-5e6f-7a8b-9c0d1e2f3a4b",
"params": ["482019"]
}
}
WhatsApp Notification
Layanan WhatsApp Notification dirancang khusus untuk pengiriman pesan transaksional dan operasional, seperti status pesanan, notifikasi pembayaran sukses, konfirmasi booking, atau perubahan akun. Layanan ini mendukung pendekatan Hybrid fleksibel:
1. Pengiriman Teks Langsung (Direct Message)
Kirimkan notifikasi langsung berupa teks bebas tanpa perlu membuat template di dashboard:
{
"xid": "notif-trx-1001",
"to": "628123456789",
"type": "notification",
"message": "Halo Budi, pembayaran invoice #INV-2049 telah berhasil dikonfirmasi. Terima kasih!"
}
2. Pengiriman Berbasis Template (Template with Parameters)
Gunakan template yang telah terdaftar dan approved di akun Anda untuk keseragaman format:
{
"xid": "notif-trx-1002",
"to": "628123456789",
"type": "notification",
"template": {
"template_id": "c8f7a1b2-3c4d-5e6f-7a8b-9c0d1e2f3a4b",
"params": ["Budi", "INV-2049", "Lunas"]
}
}
WhatsApp Reminder
Layanan WhatsApp Reminder memudahkan pengiriman pesan pengingat jatuh tempo, janji temu (appointment), jadwal konsultasi, maupun jadwal webinar. Mendukung pengiriman langsung maupun penjadwalan otomatis (Scheduled Delivery).
Penjadwalan Terjadwal (Scheduled Reminder)
Sertakan field scheduled_at dengan format ISO 8601 / RFC3339 (misal: 2026-09-25T10:00:00Z). Worker antrean asinkron MSGly akan menahan pesan dan mengeksekusinya secara presisi pada waktu yang ditentukan.
{
"xid": "rem-trx-2001",
"to": "628123456789",
"type": "reminder",
"message": "Pengingat: Jadwal janji temu dokter Anda akan berlangsung besok pukul 10:00 WIB di RS Mitra Sehat.",
"scheduled_at": "2026-09-25T10:00:00Z"
}
{
"messages": {
"id": "9d8e7f6a-1234-5678-9abc-def012345678",
"xid": "rem-trx-2001",
"status": "scheduled",
"timestamp": 1758794400000
}
}
template: { "template_id": "...", "params": [...] }.
WhatsApp Blast (Campaign)
Untuk pengiriman pesan promosi dan broadcast massal ke ribuan kontak sekaligus, MSGly menyediakan Campaign Blast Engine terintegrasi di Dashboard MSGly:
| Fitur Proteksi Blast | Mekanisme Kerja |
|---|---|
| Device Pool Auto-Distribution | Daftar penerima campaign didistribusikan secara round-robin ke seluruh device WhatsApp yang terhubung di pool akun Anda, menjaga beban kirim per device tetap seimbang. |
| Dynamic Throttling & Delays | Jeda antar pesan diacak (randomized interval delay) untuk menghindari pola pengiriman bot yang mencurigakan bagi WhatsApp. |
| Chat Presence Simulation | Worker otomatis mengirimkan sinyal composing (mengetik) beberapa detik sebelum pesan dikirimkan, mensimulasikan perilaku pengguna manusia asli. |
| Realtime Stop & Pause | Campaign dapat dipause, dibatalkan, atau dijadwalkan secara real-time langsung melalui dashboard. |
Webhooks & Delivery Status
Daftarkan Webhook URL pada pengaturan API Client Anda untuk menerima notifikasi callback secara real-time saat status pesan berubah.
Siklus Status Pengiriman (Delivery Lifecycle)
queued: Pesan berhasil diterima oleh API dan masuk ke antrean worker Redis.sent: Pesan berhasil dikirimkan oleh device WhatsApp gateway ke server WhatsApp.delivered: Pesan telah sampai di perangkat penerima (centang dua abu-abu).read: Pesan telah dibuka dan dibaca oleh penerima (centang dua biru).failed: Pesan gagal terkirim (misal: nomor tujuan tidak terdaftar di WhatsApp atau device gateway offline).
{
"event": "message.status",
"data": {
"id": "7c4817a5-d85c-48c0-845f-c9ab579899eb",
"xid": "trx-unique-001",
"recipient": "628123456789",
"status": "delivered",
"oid": "3EB0B892819024D98A",
"timestamp": 1718451125000,
"error": ""
}
}
2xx atau terjadi timeout. Pastikan endpoint webhook Anda mengembalikan respon HTTP 200 OK dengan cepat.
Error Codes & Response
Jika terjadi kendala validasi, autentikasi, atau saldo, API akan mengembalikan HTTP status code yang sesuai beserta objek error berformat JSON:
{
"error": {
"message": "duplicate xid"
}
}
| HTTP Status | Pesan Error | Penyebab & Solusi |
|---|---|---|
400 Bad Request |
duplicate xid |
Nilai xid ini sudah pernah digunakan sebelumnya. Gunakan ID unik yang baru untuk setiap transaksi. |
400 Bad Request |
invalid phone number |
Nomor penerima tidak valid atau memiliki format karakter yang salah. |
400 Bad Request |
insufficient balance |
Saldo wallet akun Anda tidak mencukupi untuk memproses pengiriman pesan. Lakukan topup saldo melalui dashboard. |
400 Bad Request |
template not found |
UUID template_id yang dikirim tidak ditemukan atau belum disetujui. |
400 Bad Request |
WhatsApp Notification service is currently disabled by administrator. |
Layanan WhatsApp Notification sedang dinonaktifkan di pengaturan sistem oleh administrator. |
400 Bad Request |
WhatsApp Reminder service is currently disabled by administrator. |
Layanan WhatsApp Reminder sedang dinonaktifkan di pengaturan sistem oleh administrator. |
400 Bad Request |
Single message service is currently disabled by administrator. |
Layanan Single message sedang dinonaktifkan di pengaturan sistem oleh administrator. |
401 Unauthorized |
The access token has expired |
Access token OAuth 2.0 telah habis masa berlakunya. Lakukan request token baru via /oauth/token. |
429 Too Many Requests |
rate limit exceeded |
Jumlah request melebihi batas rate limit akun Anda (default: 100 req/menit). Tunggu beberapa saat sebelum mencoba kembali. |
Rate Limits
Untuk menjaga kestabilan sistem dan mencegah lonjakan lalu lintas yang tidak wajar, setiap API Client memiliki batasan kecepatan request:
| Area Endpoint | Default Limit | Mekanisme Kontrol |
|---|---|---|
POST /api/v1/message |
100 request / menit per Client ID | Redis distributed rate limiter (Sliding Window). Hubungi tim sales jika aplikasi Anda memerlukan limit throughput lebih besar. |
POST /api/v1/oauth/token |
20 request / menit per IP | Proteksi brute-force token generation. Simpan token selama 24 jam. |
Official SDKs & Libraries
MSGly menyediakan pustaka (SDK) resmi untuk mempermudah integrasi ke backend Anda tanpa perlu mengelola OAuth token refresh, serialisasi JSON, ataupun parsing error secara manual.
| Bahasa | Package Manager | Perintah Instalasi |
|---|---|---|
| Node.js (JS/TS) | NPM | npm install msgly-sdk |
| Go (Golang) | Go Modules | go get github.com/msgly-official/msgly-sdk-go |
| Python | PyPI | pip install msgly-sdk |
| PHP | Composer | composer require msgly/msgly-sdk-php |
| Java | JitPack (Maven / Gradle) | com.github.msgly-official:msgly-sdk-java:v1.0.0 |
Contoh Integrasi Lengkap per Bahasa
import { MsglyClient } from 'msgly-sdk';
const msgly = new MsglyClient({
baseUrl: 'https://api.msgly.id', // Opsional, default https://api.msgly.id
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET'
});
// 1. Kirim WhatsApp OTP (Mode Rotasi Otomatis)
try {
const otpResponse = await msgly.message.sendOTP({
xid: 'otp_' + Date.now(),
to: '6281234567890',
code: '482910'
});
console.log('OTP Queued ID:', otpResponse.messages.id);
} catch (error) {
console.error('Gagal mengirim OTP:', error.message);
}
// 2. Kirim WhatsApp Notification
try {
const notifResponse = await msgly.message.sendNotification({
xid: 'notif_' + Date.now(),
to: '6281234567890',
message: 'Halo, pesanan Anda #INV-1029 telah selesai diproses.'
});
console.log('Notification Queued ID:', notifResponse.messages.id);
} catch (error) {
console.error('Gagal mengirim notifikasi:', error.message);
}
// 3. Kirim WhatsApp Reminder (Terjadwal)
try {
const reminderResponse = await msgly.message.sendReminder({
xid: 'rem_' + Date.now(),
to: '6281234567890',
message: 'Pengingat: Jadwal janji temu dokter Anda besok pukul 10:00 WIB.',
scheduled_at: new Date(Date.now() + 24 * 60 * 60 * 1000)
});
console.log('Reminder Queued/Scheduled ID:', reminderResponse.messages.id);
} catch (error) {
console.error('Gagal mengirim reminder:', error.message);
}
package main
import (
"context"
"fmt"
"log"
"time"
msgly "github.com/msgly-official/msgly-sdk-go"
)
func main() {
client := msgly.New(msgly.Config{
BaseURL: "https://api.msgly.id",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
})
ctx := context.Background()
// 1. Kirim WhatsApp OTP (Mode Rotasi Otomatis)
otpResp, err := client.Message.SendOTP(ctx, msgly.SendOTPRequest{
XID: fmt.Sprintf("otp_%d", time.Now().Unix()),
To: "6281234567890",
Code: "482910",
})
if err != nil {
log.Fatalf("Error kirim OTP: %v", err)
}
fmt.Printf("OTP Queued! ID: %s, Status: %s\n", otpResp.Messages.ID, otpResp.Messages.Status)
// 2. Kirim WhatsApp Notification
notifResp, err := client.Message.SendNotification(ctx, msgly.SendNotificationRequest{
XID: fmt.Sprintf("notif_%d", time.Now().Unix()),
To: "6281234567890",
Message: "Halo Budi, pesanan #INV-1029 Anda telah selesai diproses.",
})
if err != nil {
log.Fatalf("Error kirim notifikasi: %v", err)
}
fmt.Printf("Notification Queued! ID: %s\n", notifResp.Messages.ID)
// 3. Kirim WhatsApp Reminder (Terjadwal)
sendAt := time.Now().Add(24 * time.Hour)
reminderResp, err := client.Message.SendReminder(ctx, msgly.SendReminderRequest{
XID: fmt.Sprintf("rem_%d", time.Now().Unix()),
To: "6281234567890",
Message: "Pengingat: Jadwal konsultasi Anda terkonfirmasi besok pukul 10:00 WIB.",
ScheduledAt: &sendAt,
})
if err != nil {
log.Fatalf("Error kirim reminder: %v", err)
}
fmt.Printf("Reminder Queued/Scheduled! ID: %s\n", reminderResp.Messages.ID)
}
import time
from msgly import MsglyClient
client = MsglyClient(
client_id="YOUR_CLIENT_ID",
client_secret="YOUR_CLIENT_SECRET",
base_url="https://api.msgly.id"
)
# 1. Kirim WhatsApp OTP (Mode Rotasi Otomatis)
try:
otp_resp = client.message.send_otp(
xid=f"otp_{int(time.time())}",
to="6281234567890",
code="482910"
)
print("OTP Queued ID:", otp_resp["messages"]["id"])
except Exception as e:
print("Error kirim OTP:", e)
# 2. Kirim WhatsApp Notification
try:
notif_resp = client.message.send_notification(
xid=f"notif_{int(time.time())}",
to="6281234567890",
message="Halo Budi, status pesanan #INV-1029 Anda telah selesai diproses."
)
print("Notification Queued ID:", notif_resp["messages"]["id"])
except Exception as e:
print("Error kirim notifikasi:", e)
# 3. Kirim WhatsApp Reminder (Terjadwal)
try:
rem_resp = client.message.send_reminder(
xid=f"rem_{int(time.time())}",
to="6281234567890",
message="Pengingat: Jadwal webinar Anda akan dimulai besok pukul 10:00 WIB.",
scheduled_at="2026-09-25T10:00:00Z"
)
print("Reminder Queued/Scheduled ID:", rem_resp["messages"]["id"])
except Exception as e:
print("Error kirim reminder:", e)
<?php
require_once 'vendor/autoload.php';
use Msgly\MsglyClient;
use Msgly\Exceptions\MsglyException;
$msgly = new MsglyClient([
'base_url' => 'https://api.msgly.id',
'client_id' => 'YOUR_CLIENT_ID',
'client_secret' => 'YOUR_CLIENT_SECRET',
]);
// 1. Kirim WhatsApp OTP (Mode Rotasi Otomatis)
try {
$result = $msgly->message()->sendOTP([
'xid' => 'otp_' . time(),
'to' => '6281234567890',
'code' => '482910',
]);
echo "OTP Queued! ID: " . $result['messages']['id'] . PHP_EOL;
} catch (MsglyException $e) {
echo "Gagal kirim OTP: " . $e->getMessage() . PHP_EOL;
}
// 2. Kirim WhatsApp Notification
try {
$notif = $msgly->message()->sendNotification([
'xid' => 'notif_' . time(),
'to' => '6281234567890',
'message' => 'Halo, pesanan Anda #ORD-998 telah kami kirim via kurir.',
]);
echo "Notifikasi Queued! ID: " . $notif['messages']['id'] . PHP_EOL;
} catch (MsglyException $e) {
echo "Gagal kirim notifikasi: " . $e->getMessage() . PHP_EOL;
}
// 3. Kirim WhatsApp Reminder (Terjadwal)
try {
$reminder = $msgly->message()->sendReminder([
'xid' => 'rem_' . time(),
'to' => '6281234567890',
'message' => 'Pengingat: Jadwal janji temu Anda besok pukul 10:00 WIB.',
'scheduled_at' => date('c', strtotime('+1 day')),
]);
echo "Reminder Queued! ID: " . $reminder['messages']['id'] . PHP_EOL;
} catch (MsglyException $e) {
echo "Gagal kirim reminder: " . $e->getMessage() . PHP_EOL;
}
?>
import id.msgly.MsglyClient;
import id.msgly.message.SendMessageRequest;
import id.msgly.message.SendMessageResponse;
public class App {
public static void main(String[] args) {
MsglyClient client = MsglyClient.builder()
.baseUrl("https://api.msgly.id")
.clientId("YOUR_CLIENT_ID")
.clientSecret("YOUR_CLIENT_SECRET")
.build();
// 1. Kirim WhatsApp OTP (Mode Rotasi Otomatis)
try {
SendMessageResponse otpResp = client.message().sendOtp(
SendMessageRequest.builder()
.xid("otp_" + System.currentTimeMillis())
.to("6281234567890")
.code("482910")
.build()
);
System.out.println("OTP Queued ID: " + otpResp.getMessages().getId());
} catch (Exception e) {
e.printStackTrace();
}
// 2. Kirim WhatsApp Notification
try {
SendMessageResponse notifResp = client.message().sendNotification(
SendMessageRequest.builder()
.xid("notif_" + System.currentTimeMillis())
.to("6281234567890")
.message("Halo Budi, status pesanan #INV-1029 telah selesai.")
.build()
);
System.out.println("Notification Queued ID: " + notifResp.getMessages().getId());
} catch (Exception e) {
e.printStackTrace();
}
// 3. Kirim WhatsApp Reminder (Terjadwal)
try {
SendMessageResponse remResp = client.message().sendReminder(
SendMessageRequest.builder()
.xid("rem_" + System.currentTimeMillis())
.to("6281234567890")
.message("Pengingat: Jadwal webinar Anda dimulai besok pukul 10:00 WIB.")
.scheduledAt("2026-09-25T10:00:00Z")
.build()
);
System.out.println("Reminder Queued/Scheduled ID: " + remResp.getMessages().getId());
} catch (Exception e) {
e.printStackTrace();
}
}
}
