Spesifikasi parameter, integrasi device headless (QR / Pairing Code via API), WhatsApp Messaging, Phonebook, OTP Engine, dan Webhooks siap pakai.
QIRIM menggunakan arsitektur 2-Tier Authentication yang fleksibel dan aman untuk integrasi backend web maupun sistem mikroservis:
Format: qirim_sec_...
Digunakan oleh backend server Anda untuk mengelola perangkat (membuat device baru, mengambil Base64 QR Code, pairing code, dan menghapus device) serta pengiriman pesan otomatis.
Authorization: Bearer qirim_sec_...x-client-secret: qirim_sec_...
Format: qirim_live_...
Dibuat khusus untuk setiap line WhatsApp terdaftar. Digunakan untuk mengirim pesan, media, OTP, broadcast dari nomor WhatsApp spesifik tersebut.
Authorization: Bearer qirim_live_...x-api-key: qirim_live_...
https://qirim.web.id/api/v1
Authorization: Bearer <CLIENT_SECRET_ATAU_DEVICE_API_KEY>
Content-Type: application/json
Endpoint publik (tanpa API key) untuk monitoring server uptime (BetterUptime, UptimeKuma) dan cron keep-alive:
GET https://qirim.web.id/api/v1/health
# Response (200 OK): {"status": true, "engine": "qirim by alula", "timestamp": "2026-10-06T08:50:00.000Z"}
Kirim pesan teks personal atau grup WhatsApp dengan simulasi mengetik manusia (humanized delay) dan dukungan variasi teks Spintax {Halo|Hai|Selamat Pagi}.
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
target |
String | Ya | Nomor WhatsApp tujuan (contoh: 081234567890 atau 6281234567890) atau ID Grup (...-group@g.us). |
message |
String | Ya | Isi pesan teks. Mendukung Spintax {Halo|Hai} Kak. |
curl -X POST https://qirim.web.id/api/v1/send-message \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target": "081234567890",
"message": "{Halo|Hai} Kak! Pesanan Anda telah kami terima dan sedang diproses."
}'<?php
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('QIRIM_API_KEY'),
])->post('https://qirim.web.id/api/v1/send-message', [
'target' => '081234567890',
'message' => 'Halo Kak, tagihan Anda sebesar Rp 150.000 telah terbit.',
]);
return $response->json();const axios = require('axios');
const res = await axios.post('https://qirim.web.id/api/v1/send-message', {
target: '081234567890',
message: 'Hello from Node.js!'
}, {
headers: { 'Authorization': 'Bearer ' + process.env.QIRIM_API_KEY }
});
console.log(res.data);import requests
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"target": "081234567890",
"message": "Halo dari Python script!"
}
response = requests.post("https://qirim.web.id/api/v1/send-message", json=payload, headers=headers)
print(response.json()){
"status": true,
"message": "Message sent successfully",
"data": {
"id": "3EB09F2184912...",
"target": "081234567890",
"device_id": 1,
"timestamp": "2026-09-06T09:00:00.000Z"
}
}
QIRIM mendukung pengiriman semua jenis lampiran media WhatsApp (Gambar JPG/PNG/WebP, Dokumen PDF/DOCX/XLSX/ZIP/CSV/TXT, Audio & Voice Note PTT, Video MP4). API mendukung dua mode pengiriman yang fleksibel:
Upload file langsung dari server atau aplikasi lokal Anda menggunakan header Content-Type: multipart/form-data dengan nama field file atau media (Maksimal 50MB).
Kirim URL file publik yang dapat diunduh (misal: https://domain.com/faktur.pdf) atau Data URI Base64 menggunakan header Content-Type: application/json.
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
target / phone |
String | Ya | Nomor WhatsApp tujuan (contoh: 081234567890 atau 6281234567890) atau Group ID. |
file / url / media_url |
File / String | Ya | File biner yang diunggah via form-data (field file) ATAU URL file publik / Data URI Base64. |
type |
String | Opsional |
Jenis media: image, document, file, audio, voice, video.(Otomatis dideteksi dari ekstensi file jika tidak dicantumkan). |
caption / message |
String | Opsional | Teks keterangan yang menyertai file media. Mendukung Spintax {Halo|Hai}. |
filename |
String | Opsional | Nama tampilan file saat dikirim sebagai dokumen (contoh: Invoice-INV-202609.pdf). |
ptt / is_voice |
Boolean | Opsional | Set true jika audio ingin dikirimkan sebagai Voice Note (PTT) dengan ikon mikrofon hijau. |
# 1. Kirim Dokumen PDF / Invoice Langsung via Upload
curl -X POST https://qirim.web.id/api/v1/send-document \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "target=081234567890" \
-F "file=@/path/to/invoice.pdf" \
-F "filename=Invoice-INV-2026.pdf" \
-F "caption=Halo Kak, berikut lampiran invoice resmi pesanan Anda."
# 2. Kirim Foto / Gambar Langsung via Upload
curl -X POST https://qirim.web.id/api/v1/send-image \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "target=081234567890" \
-F "file=@/path/to/promo.jpg" \
-F "caption=Promo Spesial Hari Ini! Diskon hingga 50%."curl -X POST https://qirim.web.id/api/v1/send-media \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target": "081234567890",
"type": "document",
"url": "https://domain.com/downloads/slip-gaji-september.pdf",
"filename": "Slip_Gaji_September.pdf",
"caption": "Lampiran slip gaji karyawan periode September 2026."
}'<?php
use Illuminate\Support\Facades\Http;
// Contoh A: Upload File Lokal (PDF Invoice)
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('QIRIM_API_KEY'),
])->attach(
'file', file_get_contents(storage_path('app/invoices/inv-001.pdf')), 'Invoice-001.pdf'
)->post('https://qirim.web.id/api/v1/send-document', [
'target' => '081234567890',
'caption' => 'Terima kasih atas pembayaran Anda!',
]);
return $response->json();
// Contoh B: Kirim Gambar via URL Publik
$resImg = Http::withHeaders([
'Authorization' => 'Bearer ' . env('QIRIM_API_KEY'),
])->post('https://qirim.web.id/api/v1/send-image', [
'target' => '081234567890',
'url' => 'https://domain.com/images/banner.png',
'caption' => 'Katalog Produk Terbaru 2026',
]);<?php
$ch = curl_init();
$filePath = realpath('slip-gaji.pdf');
$postData = [
'target' => '081234567890',
'file' => new CURLFile($filePath, 'application/pdf', 'Slip-Gaji.pdf'),
'caption' => 'Slip Gaji Resmi Anda',
'filename' => 'Slip-Gaji.pdf'
];
curl_setopt($ch, CURLOPT_URL, 'https://qirim.web.id/api/v1/send-document');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer YOUR_API_KEY'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
echo $result;const axios = require('axios');
const fs = require('fs');
const FormData = require('form-data');
// 1. Upload File Lokal (Dokumen / PDF / Gambar)
async function sendLocalDocument() {
const form = new FormData();
form.append('target', '081234567890');
form.append('caption', 'Berikut file laporan bulanan.');
form.append('filename', 'Laporan-Q3.pdf');
form.append('file', fs.createReadStream('./laporan.pdf'));
const res = await axios.post('https://qirim.web.id/api/v1/send-document', form, {
headers: {
...form.getHeaders(),
'Authorization': 'Bearer ' + process.env.QIRIM_API_KEY
}
});
console.log(res.data);
}
// 2. Kirim Gambar / Voice Note via Remote URL
async function sendRemoteMedia() {
const res = await axios.post('https://qirim.web.id/api/v1/send-media', {
target: '081234567890',
type: 'image',
url: 'https://images.unsplash.com/photo-1579546929518-9e396f3cc809',
caption: 'Foto pemandangan indah!'
}, {
headers: { 'Authorization': 'Bearer ' + process.env.QIRIM_API_KEY }
});
console.log(res.data);
}import requests
API_KEY = "YOUR_API_KEY"
headers = {"Authorization": f"Bearer {API_KEY}"}
# 1. Upload File Lokal Langsung (PDF / Word / Excel / Image)
with open("invoice.pdf", "rb") as f:
files = {"file": ("Invoice-2026.pdf", f, "application/pdf")}
data = {
"target": "081234567890",
"caption": "Halo Kak, ini invoice pesanan Anda."
}
res = requests.post("https://qirim.web.id/api/v1/send-document", headers=headers, data=data, files=files)
print(res.json())
# 2. Kirim Voice Note PTT via URL
voice_payload = {
"target": "081234567890",
"type": "voice",
"url": "https://domain.com/audio/greeting.mp3",
"ptt": True
}
res_voice = requests.post("https://qirim.web.id/api/v1/send-voice", headers=headers, json=voice_payload)
print(res_voice.json()){
"status": true,
"message": "DOCUMENT sent successfully",
"data": {
"id": "3EB09F2184912...",
"target": "081234567890",
"type": "document",
"media": "Invoice-INV-2026.pdf",
"filename": "Invoice-INV-2026.pdf",
"device_id": 1,
"timestamp": "2026-09-06T09:00:00.000Z"
}
}
Kirim pin koordinat lokasi Google Maps langsung ke ruang obrolan WhatsApp pelanggan.
curl -X POST https://qirim.web.id/api/v1/send-location \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target": "081234567890",
"latitude": -6.200000,
"longitude": 106.816666,
"name": "Kantor Pusat",
"address": "Jl. Jenderal Sudirman No. 1, Jakarta"
}'Kirim kartu kontak (vCard) interaktif yang bisa langsung disimpan ke buku kontak penerima dengan satu ketukan.
curl -X POST https://qirim.web.id/api/v1/send-contact \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target": "081234567890",
"contact_name": "Customer Support",
"contact_phone": "628999888777"
}'Kirim pesan menggunakan template tersimpan dengan penggantian variabel dinamis seperti {name}, {order_id}, {total}.
curl -X POST https://qirim.web.id/api/v1/send-template \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target": "081234567890",
"template_name": "Konfirmasi Pembayaran",
"variables": {
"name": "Budi Santoso",
"order_id": "INV-2026-001",
"total": "Rp 250.000"
}
}'Kirim pesan massal ke banyak nomor sekaligus secara asynchronous di background dengan proteksi interval pengiriman cerdas (rate limiting).
curl -X POST https://qirim.web.id/api/v1/broadcast \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipients": ["081234567890", "081234567891", "081234567892"],
"message": "{Halo|Hai} Pelanggan setia, nikmati promo spesial hari ini!",
"delay_seconds": 3
}'Jadwalkan pengiriman pesan di masa depan (one-time) atau berulang otomatis (daily, weekly, monthly).
curl -X POST https://qirim.web.id/api/v1/schedule-message \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target": "081234567890",
"message": "Pengingat: Tagihan bulanan Anda jatuh tempo besok.",
"schedule_time": "2026-09-15 09:00:00",
"recurring_type": "monthly"
}'| Method & Endpoint | Fungsi |
|---|---|
GET /api/v1/scheduled |
Mendapatkan daftar seluruh pesan terjadwal akun Anda. |
DELETE /api/v1/scheduled/:id |
Membatalkan atau menghapus antrean jadwal pesan. |
Engine One-Time Password (OTP) & Two-Factor Authentication (2FA) resmi bawaan Qirim.
Menghasilkan token angka kriptografis acak (secure CSPRNG), pembatasan durasi masa berlaku (TTL countdown), verifikasi Single-Use Token (anti replay-attack), serta dukungan kustomisasi pesan template dengan variabel {otp} dan {expiry}.
Endpoint: POST /api/v1/otp/send atau POST /api/v1/2fa/send
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
target / phone |
String | Ya | Nomor WhatsApp tujuan penerima OTP (contoh: 081234567890 atau 6281234567890). |
length / digits |
Integer | Opsional | Panjang digit kode OTP (default: 6 digit, rentang: 4 - 8 digit). |
expiry_minutes / expiry |
Integer | Opsional | Masa berlaku kode dalam menit (default: 5 menit). |
type |
String | Opsional | Tipe kode: otp atau 2fa (default: otp). |
template |
String | Opsional | Format teks pesan kustom. Gunakan placeholder {otp} untuk kode dan {expiry} untuk durasi menit. |
curl -X POST https://qirim.web.id/api/v1/otp/send \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target": "081234567890",
"length": 6,
"expiry_minutes": 5,
"type": "2fa",
"template": "🔒 [2FA] Kode rahasia login Anda: {otp}. Berlaku {expiry} menit. Jangan berikan ke siapapun!"
}'<?php
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('QIRIM_API_KEY'),
])->post('https://qirim.web.id/api/v1/otp/send', [
'target' => '081234567890',
'length' => 6,
'expiry_minutes' => 5,
'type' => 'otp'
]);
return $response->json();const axios = require('axios');
const res = await axios.post('https://qirim.web.id/api/v1/otp/send', {
target: '081234567890',
length: 6,
expiry_minutes: 5,
type: '2fa'
}, {
headers: { 'Authorization': 'Bearer ' + process.env.QIRIM_API_KEY }
});
console.log(res.data);import requests
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"target": "081234567890",
"length": 6,
"expiry_minutes": 5,
"type": "otp"
}
response = requests.post("https://qirim.web.id/api/v1/otp/send", json=payload, headers=headers)
print(response.json()){
"status": true,
"message": "2FA sent successfully to WhatsApp target.",
"data": {
"otp_id": 42,
"target": "081234567890",
"type": "2fa",
"expires_at": "2026-09-18T08:35:00.000Z",
"message_id": "3EB0B8E7A12..."
}
}
Endpoint: POST /api/v1/otp/verify atau POST /api/v1/2fa/verify
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
target / phone |
String | Ya | Nomor WhatsApp pengguna yang diverifikasi (contoh: 081234567890). |
otp_code / code / otp |
String | Ya | Kode angka yang diterima dan diinput oleh user (contoh: "849201"). |
curl -X POST https://qirim.web.id/api/v1/otp/verify \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target": "081234567890",
"otp_code": "849201"
}'<?php
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('QIRIM_API_KEY'),
])->post('https://qirim.web.id/api/v1/otp/verify', [
'target' => '081234567890',
'otp_code' => $request->input('otp_code'),
]);
if ($response->successful()) {
// OTP VALID -> Berhasil Login / Verifikasi
return redirect('/dashboard');
} else {
// OTP SALAH / KADALUARSA
return back()->withErrors(['otp' => $response->json('message')]);
}const axios = require('axios');
try {
const res = await axios.post('https://qirim.web.id/api/v1/otp/verify', {
target: '081234567890',
otp_code: req.body.otp_code
}, {
headers: { 'Authorization': 'Bearer ' + process.env.QIRIM_API_KEY }
});
console.log('OTP Valid!', res.data);
} catch (err) {
console.error('OTP Invalid or Expired:', err.response?.data?.message);
}import requests
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"target": "081234567890",
"otp_code": "849201"
}
response = requests.post("https://qirim.web.id/api/v1/otp/verify", json=payload, headers=headers)
data = response.json()
if response.status_code == 200 and data.get("status"):
print("Verifikasi Berhasil:", data["data"])
else:
print("Gagal:", data.get("message")){
"status": true,
"message": "OTP verified successfully.",
"data": {
"otp_id": 42,
"target": "081234567890",
"type": "2fa",
"verified_at": "2026-09-18T08:31:15.000Z"
}
}
{
"status": false,
"message": "Invalid OTP code or already used."
}
// ATAU jika sudah lewat masa berlaku:
{
"status": false,
"message": "OTP code has expired. Please request a new one."
}
Setiap pesan OTP & 2FA yang dikirimkan dapat menyertakan token laporan {report_link}. Jika pemilik nomor mengeklik tautan tersebut karena tidak merasa melakukan login/registrasi, sistem Qirim akan segera membatalkan semua OTP aktif dan membekukan nomor tersebut selama 24 jam dari segala permintaan OTP dan login baru.
{
"status": false,
"locked": true,
"remaining_hours": "23.8",
"expires_at": "2026-09-19T14:30:00.000Z",
"message": "⛔ Permintaan OTP / Login ke nomor 081234567890 telah DITANGGUHKAN sementara selama 24 jam demi keamanan akun karena adanya laporan insiden keamanan."
}
{
"status": false,
"rate_limited": true,
"reason": "burst_limit",
"message": "Terlalu banyak permintaan OTP dalam waktu singkat (3/3). Harap tunggu 15 menit sebelum meminta kode baru demi keamanan."
}
| Method & Endpoint | Fungsi | Contoh Payload / Query |
|---|---|---|
GET /api/v1/security/lockouts |
Memeriksa apakah suatu nomor sedang dalam status penangguhan / terkunci 24 jam. | ?phone=081234567890 |
POST /api/v1/security/report-incident |
Membekukan nomor atau memproses token laporan keamanan secara programmatic. | {"phone": "081234567890", "reason": "Fraud suspected"} |
Integrasi manajemen perangkat secara headless dari aplikasi/web Anda sendiri (render QR Code di website Anda, generate pairing code, atau buat perangkat baru via API).
| Method & Endpoint | Fungsi | Payload / Keterangan |
|---|---|---|
GET /api/v1/devices |
Daftar semua perangkat akun | Mengembalikan status live gateway dan sisa kuota tiap perangkat. |
POST /api/v1/devices |
Buat perangkat baru via API | Body: {"name": "Device Kasir", "webhook_url": "https://..."} |
GET /api/v1/device/status |
Status perangkat aktif | Status koneksi (connected, scan_qr, disconnected) & kuota. |
GET /api/v1/device/qr |
Dapatkan QR Code Base64 | Mengembalikan qr_image_url (Data URL) untuk disematkan langsung di <img src="..."> web Anda. |
POST /api/v1/device/pairing-code |
Generate Pairing Code 8 digit | Body: {"phone": "081234567890"} untuk koneksi WhatsApp via nomor telepon. |
POST /api/v1/device/regenerate-key |
Regenerate API Key | Menghasilkan API Key baru secara instan dan menonaktifkan key lama. |
POST /api/v1/device/disconnect |
Disconnect / Logout Session | Memutus koneksi socket WhatsApp dan membersihkan session auth. |
POST /api/v1/device/restart |
Restart Socket (Zero Unlink) | Memperbarui koneksi socket WhatsApp secara instan tanpa logout/unpair dan tanpa perlu scan QR ulang. Memulihkan socket zombie/stalled dan memperpanjang sewa saluran channel. (Mendukung alias: /devices/:id/restart, /device/reconnect, /devices/:id/reconnect). |
POST /api/v1/webhook/set |
Set / Update Webhook URL | Body: {"webhook_url": "https://...", "channel_jid": "...", "channel_name": "..."}. Mengatur endpoint webhook perangkat sekaligus mendaftarkan pemantauan saluran jika disertakan. |
# 1. Buat Device Baru
curl -X POST https://qirim.web.id/api/v1/devices \
-H "Authorization: Bearer YOUR_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-d '{"name": "WhatsApp Web User", "webhook_url": "https://mysite.com/webhook"}'
# 2. Ambil QR Code Base64 untuk ditampilkan di Web Frontend
curl -X GET https://qirim.web.id/api/v1/devices/1/qr \
-H "Authorization: Bearer YOUR_CLIENT_SECRET"
# 3. Atau Minta Pairing Code 8-Digit via Nomor WhatsApp
curl -X POST https://qirim.web.id/api/v1/devices/1/pairing-code \
-H "Authorization: Bearer YOUR_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-d '{"phone": "6281234567890"}'
# 4. Restart / Power-Cycle Socket WhatsApp (Tanpa Unlink / Tanpa Scan QR)
curl -X POST https://qirim.web.id/api/v1/devices/1/restart \
-H "Authorization: Bearer YOUR_CLIENT_SECRET"<?php
use Illuminate\Support\Facades\Http;
// 1. Mengambil QR Code Base64 untuk tag <img src="...">
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('QIRIM_CLIENT_SECRET'),
])->get('https://qirim.web.id/api/v1/devices/' . $deviceId . '/qr');
$data = $response->json();
if ($data['status'] && !empty($data['qr_image_url'])) {
echo '<img src="' . $data['qr_image_url'] . '" alt="Scan QR WA" />';
}
// 2. Restart / Reconnect Socket Tanpa Logout (Auto-Recovery)
$restartRes = Http::withHeaders([
'Authorization' => 'Bearer ' . env('QIRIM_CLIENT_SECRET'),
])->post('https://qirim.web.id/api/v1/devices/' . $deviceId . '/restart');const axios = require('axios');
// 1. Buat device dan inisialisasi sesi WhatsApp
const createRes = await axios.post('https://qirim.web.id/api/v1/devices', {
name: 'Device Kasir Toko'
}, {
headers: { 'Authorization': 'Bearer ' + process.env.QIRIM_CLIENT_SECRET }
});
const deviceId = createRes.data.data.id;
// 2. Ambil data QR Code Data URL
const qrRes = await axios.get(`https://qirim.web.id/api/v1/devices/${deviceId}/qr`, {
headers: { 'Authorization': 'Bearer ' + process.env.QIRIM_CLIENT_SECRET }
});
console.log('QR Data URL:', qrRes.data.qr_image_url);
// 3. Restart / Reconnect Socket Tanpa Logout (Zero-Unlink)
const restartRes = await axios.post(`https://qirim.web.id/api/v1/devices/${deviceId}/restart`, {}, {
headers: { 'Authorization': 'Bearer ' + process.env.QIRIM_CLIENT_SECRET }
});
console.log('Restart Socket:', restartRes.data.message);import requests
headers = {
"Authorization": "Bearer YOUR_CLIENT_SECRET",
"Content-Type": "application/json"
}
# 1. Ambil QR code untuk device ID tertentu
resp = requests.get("https://qirim.web.id/api/v1/devices/1/qr", headers=headers)
data = resp.json()
print("Status Koneksi:", data.get("connection_status"))
print("QR Data URL:", data.get("qr_image_url"))
# 2. Restart socket perangkat tanpa logout
restart_resp = requests.post("https://qirim.web.id/api/v1/devices/1/restart", headers=headers)
print("Restart Result:", restart_resp.json().get("message")){
"status": true,
"device_id": 1,
"connection_status": "scan_qr",
"is_connected": false,
"qr_image_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"pairing_code": null,
"message": "QR code generated. Display qr_image_url as <img src=\"...\">"
}
{
"status": true,
"message": "Device #1 (Device Kasir) session restarted successfully. Reconnecting socket in background without unlinking.",
"device_id": 1,
"connection_status": "reconnecting"
}
Kelola buku kontak dan pengelompokan pelanggan Anda via REST API.
| Method & Endpoint | Keterangan |
|---|---|
GET /api/v1/contacts |
Ambil daftar kontak (mendukung filter ?group_id=...). |
POST /api/v1/contacts |
Tambah kontak: {"name": "Budi", "phone": "081234567890", "group_id": 1, "custom_var1": "VIP"}. |
DELETE /api/v1/contacts/:id |
Hapus kontak berdasarkan ID. |
GET /api/v1/groups |
Ambil daftar grup kontak dan jumlah anggota tiap grup. |
POST /api/v1/groups |
Tambah grup kontak baru: {"name": "Pelanggan VIP", "description": "Grup prioritas"}. |
DELETE /api/v1/groups/:id |
Hapus grup kontak berdasarkan ID. |
Kelola aturan respon otomatis bot WhatsApp (Teks Statis / Template Spintax maupun Dynamic AI Custom Prompt).
| Method & Endpoint | Keterangan & Contoh Payload |
|---|---|
GET /api/v1/autoreply |
Ambil daftar seluruh aturan auto-reply pada perangkat ini. |
POST /api/v1/autoreply |
Tambah aturan Teks Statis atau AI Prompt:
|
DELETE /api/v1/autoreply/:id |
Hapus aturan auto-reply berdasarkan ID. |
Kelola template pesan siap pakai untuk kampanye dan notifikasi.
| Method & Endpoint | Keterangan & Contoh Payload |
|---|---|
GET /api/v1/templates |
Dapatkan daftar seluruh template pesan tersimpan. |
POST /api/v1/templates |
Buat template baru:
|
DELETE /api/v1/templates/:id |
Hapus template pesan berdasarkan ID. |
Cek profil akun, paket langganan aktif, fitur yang diizinkan oleh paket, dan akumulasi penggunaan kuota pesan.
curl -X GET https://qirim.web.id/api/v1/account \
-H "Authorization: Bearer YOUR_API_KEY"Qirim mengirimkan notifikasi HTTP POST real-time ke URL Webhook yang Anda daftarkan di perangkat setiap kali terjadi pesan masuk, postingan saluran baru, status story, maupun perubahan koneksi perangkat.
X-Hub-Signature-256: sha256=<hmac_hex_digest>X-Webhook-Token: <YOUR_DEVICE_API_KEY>X-Api-Key: <YOUR_DEVICE_API_KEY><?php
// Verifikasi Webhook di PHP / Laravel
$payload = file_get_contents('php://input');
$signatureHeader = $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '';
$secret = env('QIRIM_API_KEY'); // Device API Key
$expectedSig = 'sha256=' . hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expectedSig, $signatureHeader)) {
http_response_code(401);
exit('Invalid Webhook Signature');
}
$data = json_decode($payload, true);
// Selalu kirimkan HTTP 200 OK dengan cepat
http_response_code(200);
echo json_encode(['status' => true]);const crypto = require('crypto');
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-hub-signature-256'] || '';
const secret = process.env.QIRIM_API_KEY;
const hmac = 'sha256=' + crypto.createHmac('sha256', secret).update(req.body).digest('hex');
if (signature !== hmac) {
return res.status(401).send('Unauthorized signature');
}
const payload = JSON.parse(req.body.toString());
console.log('Event received:', payload.event, payload.data);
// Return HTTP 200 segera untuk menghindari timeout gateway (12 detik)
res.status(200).json({ ok: true });
});messages.received (Pesan 1-on-1 Masuk){
"event": "messages.received",
"timestamp": "2026-10-06T08:30:00.000Z",
"data": {
"device_id": 1,
"device_name": "CS Support Utama",
"sender": "6281234567890",
"message": "Halo, apakah stok barang ini masih tersedia?",
"type": "text",
"is_group": false,
"timestamp": 1728203400
}
}
channel.post_received (Postingan Saluran WhatsApp Masuk)Dikirim saat saluran WhatsApp (@newsletter) yang dipantau mempublikasikan postingan baru (ditangkap via live update WebSocket maupun endpoint fetch-messages):
{
"event": "channel.post_received",
"timestamp": "2026-10-06T08:35:12.000Z",
"data": {
"device_id": 1,
"device_name": "Device KAI Updates",
"channel_jid": "120363198765432@newsletter",
"channel_name": "KAI Access Channel",
"message": "Informasi Perjalanan: Update Keterlambatan KA 202 per 06 Okt 2026.",
"type": "text",
"media_url": null,
"timestamp": 1728203712
}
}
status.received (Status / Story WhatsApp Kontak Masuk){
"event": "status.received",
"timestamp": "2026-10-06T08:36:00.000Z",
"data": {
"device_id": 1,
"device_name": "CS Support Utama",
"sender": "6289876543210",
"message": "Promo flash sale berlangsung hingga malam ini!",
"type": "text",
"media_url": null,
"timestamp": 1728203760
}
}
messages.failed (Pengiriman Pesan Gagal){
"event": "messages.failed",
"timestamp": "2026-10-06T08:37:00.000Z",
"data": {
"device_id": 1,
"target": "6281234567890",
"error": "Number not registered on WhatsApp or connection timeout",
"timestamp": 1728203820
}
}
device.connected & device.disconnected{
"event": "device.connected",
"timestamp": "2026-10-06T08:40:00.000Z",
"data": {
"device_id": 1,
"phone": "6281234567890",
"status": "connected",
"timestamp": "2026-10-06T08:40:00.000Z"
}
}
200 OK dalam waktu < 12 detik. Jika perlu proses berat (misal AI atau query panjang), masukkan ke job queue / background worker di server Anda.127.0.0.1, 10.x.x.x, 192.168.x.x) demi keamanan infrastruktur multi-tenant. Gunakan domain publik dengan HTTPS aktif.timestamp + channel_jid untuk menghindari duplikasi pemrosesan data.Scanner Pre-flight bertenaga AI Smart Engine & Heuristic Delivery Safety Rules untuk menganalisis risiko kepatuhan format pesan sebelum mengirim broadcast massal atau kampanye. Mendeteksi URL shortener mencurigakan, kata kunci pemicu spam/judol/urgensi agresif, huruf kapital berlebih, serta memberikan skor risiko (0 - 100), rekomendasi mitigasi, dan variasi pesan aman otomatis (Spintax).
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
message / text |
String | Ya | Teks isi pesan WhatsApp yang akan diuji tingkat keamanan konten dan kepatuhannya. |
curl -X POST https://qirim.web.id/api/v1/check-message-safety \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "BURUAN KLIK LINK INI SEKARANG JUGA http://bit.ly/hadiah-gratis KLAIM 500RB TANPA SYARAT DEPO CEPAT!!!"
}'<?php
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('QIRIM_API_KEY'),
])->post('https://qirim.web.id/api/v1/check-message-safety', [
'message' => 'Halo {name}, dapatkan diskon 20% khusus hari ini melalui website resmi kami.',
]);
$safety = $response->json();
if ($safety['data']['isBannable']) {
// Pesan berisiko tinggi kena banned
echo "Peringatan: Skor risiko " . $safety['data']['riskScore'] . "/100";
} else {
// Pesan aman untuk dikirim
echo "Pesan Aman! Level: " . $safety['data']['riskLevel'];
}const axios = require('axios');
const res = await axios.post('https://qirim.web.id/api/v1/check-message-safety', {
message: 'Halo Kak {name}, pesanan Anda sudah kami kirim dengan resi JNE 12345.'
}, {
headers: { 'Authorization': 'Bearer ' + process.env.QIRIM_API_KEY }
});
console.log('Skor Risiko Ban:', res.data.data.riskScore);
console.log('Rekomendasi AI:', res.data.data.suggestions);import requests
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"message": "PROMO TERBATAS HARI INI SAJA! HUBUNGI KAMI DI WA."
}
response = requests.post("https://qirim.web.id/api/v1/check-message-safety", json=payload, headers=headers)
data = response.json()
print("Risk Level:", data["data"]["riskLevel"])
print("Detected Issues:", data["data"]["detectedIssues"]){
"status": true,
"data": {
"riskScore": 65,
"riskLevel": "HIGH",
"isBannable": true,
"detectedIssues": [
"Menggunakan URL shortener (bit.ly) yang sering ditandai sebagai phishing oleh WhatsApp",
"Huruf kapital berlebih (> 30%) memicu filter spam WhatsApp",
"Kata urgensi agresif: BURUAN, SEKARANG JUGA, KLAIM GRATIS"
],
"suggestions": [
"Ganti shortlink bit.ly dengan domain website resmi Anda sendiri",
"Gunakan huruf kecil normal dengan kapitalisasi kalimat yang wajar",
"Gunakan format Spintax {Halo|Hai} untuk memvariasikan teks broadcast"
],
"safeAlternative": "{Halo|Hai} Kak {name}, berikut informasi penawaran spesial untuk Anda di website resmi kami: https://example.com"
}
}
Kelola dan ambil daftar Saluran WhatsApp (@newsletter) serta Grup WhatsApp (@g.us) secara otomatis melalui REST API, dapatkan data subscriber/member terkini, dan publikasikan siaran pengumuman berformat teks maupun media secara langsung.
Untuk menjaga stabilitas performa kueri dan pemrosesan lancar hingga 50+ saluran WhatsApp simultan, seluruh pesan saluran (@newsletter) hanya disimpan selama 24 jam di database QIRIM. Pesan yang lebih lama dari 24 jam otomatis dibersihkan oleh sistem. Anda juga dapat memicu pembersihan manual via endpoint cleanup.
GET https://qirim.web.id/api/v1/channels atau GET https://qirim.web.id/api/v1/channels/list
Mengembalikan seluruh Saluran WhatsApp yang terhubung dengan akun/perangkat. Tambahkan parameter <code>?refresh=true</code> untuk memicu sinkronisasi langsung dari WhatsApp.
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
device_id |
Integer / String | Opsional | ID Device WhatsApp spesifik. Jika kosong, sistem otomatis memakai device aktif pertama. |
refresh |
Boolean (true/1) |
Opsional | Jika true, engine akan query langsung ke WhatsApp untuk menyinkronkan subscriber dan saluran baru. |
curl -X GET "https://qirim.web.id/api/v1/channels?refresh=true" -H "Authorization: Bearer YOUR_API_KEY"<?php
use IlluminateSupportFacadesHttp;
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('QIRIM_API_KEY'),
])->get('https://qirim.web.id/api/v1/channels', [
'refresh' => 'true'
]);
$channels = $response->json();
foreach ($channels['data']['channels'] as $ch) {
echo $ch['name'] . " (" . $ch['jid'] . ") - " . $ch['subscribers'] . " subscribers\n";
}const axios = require('axios');
const res = await axios.get('https://qirim.web.id/api/v1/channels', {
headers: { 'Authorization': 'Bearer ' + process.env.QIRIM_API_KEY },
params: { refresh: 'true' }
});
console.log('Total Saluran:', res.data.data.total);
console.log(res.data.data.channels);import requests
headers = { "Authorization": "Bearer YOUR_API_KEY" }
response = requests.get("https://qirim.web.id/api/v1/channels", headers=headers, params={"refresh": "true"})
data = response.json()
for ch in data.get("data", {}).get("channels", []):
print(f"{ch['name']}: {ch['subscribers']} pengikut (JID: {ch['jid']})"){
"status": true,
"message": "Channels retrieved successfully",
"data": {
"total": 2,
"device_id": 1,
"channels": [
{
"id": 1,
"device_id": 1,
"jid": "120363144123456789@newsletter",
"name": "QIRIM Official Updates & Promo",
"subscribers": 1420,
"role": "admin",
"description": "Saluran informasi resmi, changelog, dan promo diskon layanan QIRIM.",
"last_synced_at": "2026-09-18T23:30:00.000Z"
}
]
}
}
POST https://qirim.web.id/api/v1/channels/send atau POST https://qirim.web.id/api/v1/channels/post
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
channel_jid / target |
String | Ya | JID Saluran WhatsApp tujuan (contoh: <code>120363144123456789@newsletter</code>) |
message / text |
String | Ya* | Isi teks postingan. Mendukung formatting WhatsApp (*tebal*, _miring_, ~coret~). |
media_url / file |
String / File | Opsional | URL media publik atau unggah file langsung (gambar JPG/PNG, video MP4, dokumen PDF). |
media_type |
String | Opsional | image | video | document (Otomatis dideteksi sistem). |
curl -X POST https://qirim.web.id/api/v1/channels/send -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{
"channel_jid": "120363144123456789@newsletter",
"message": "*PENGUMUMAN PENTING:* Kami baru saja merilis fitur WhatsApp Channels API! 🚀\n\nKunjungi https://qirim.web.id/docs untuk membaca dokumentasi lengkap.",
"media_url": "https://qirim.web.id/assets/images/banner-update.png"
}'<?php
use IlluminateSupportFacadesHttp;
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('QIRIM_API_KEY'),
])->post('https://qirim.web.id/api/v1/channels/send', [
'channel_jid' => '120363144123456789@newsletter',
'message' => '*UPDATE TERBARU:* Fitur baru telah aktif di dashboard.',
'media_url' => 'https://example.com/promo.jpg'
]);
$result = $response->json();
echo $result['message'];const axios = require('axios');
const res = await axios.post('https://qirim.web.id/api/v1/channels/send', {
channel_jid: '120363144123456789@newsletter',
message: 'Halo pengikut setia saluran! Berikut info promo minggu ini.',
media_url: 'https://example.com/banner.png'
}, {
headers: { 'Authorization': 'Bearer ' + process.env.QIRIM_API_KEY }
});
console.log('Post ID:', res.data.data.id);import requests
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"channel_jid": "120363144123456789@newsletter",
"message": "*Info Penting Saluran:* Jadwal pemeliharaan server malam ini jam 00:00 WIB."
}
res = requests.post("https://qirim.web.id/api/v1/channels/send", json=payload, headers=headers)
print(res.json())
POST https://qirim.web.id/api/v1/channels/fetch-messages
Mengambil postingan terkini dari satu atau beberapa Saluran WhatsApp secara aktif langsung dari server WhatsApp. Setiap pesan yang berhasil ditarik otomatis dicatat ke riwayat log database dan didistribusikan ke URL Webhook Anda (event <code>channel.post_received</code>).
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
channel_jid / target |
String | Ya | JID Saluran WhatsApp (contoh: <code>120363144123456789@newsletter</code>). Mendukung banyak JID sekaligus dipisahkan koma. |
count |
Integer | Opsional | Jumlah pesan terakhir yang ingin ditarik (default: <code>10</code>, maksimal: <code>50</code>). |
dispatch_webhook |
Boolean | Opsional | Jika true (default: <code>true</code>), setiap pesan baru otomatis diteruskan ke Webhook Anda sebagai event <code>channel.post_received</code>. |
channel_name |
String | Opsional | Nama alias saluran WhatsApp opsional. |
curl -X POST https://qirim.web.id/api/v1/channels/fetch-messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channel_jid": "120363144123456789@newsletter",
"count": 10,
"dispatch_webhook": true
}'<?php
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('QIRIM_API_KEY'),
])->post('https://qirim.web.id/api/v1/channels/fetch-messages', [
'channel_jid' => '120363144123456789@newsletter',
'count' => 15,
'dispatch_webhook' => true
]);
$data = $response->json();
echo "Berhasil mengambil " . $data['total'] . " pesan saluran.\n";
foreach ($data['data'] as $msg) {
echo "[" . $msg['timestamp'] . "] " . $msg['message'] . "\n";
}const axios = require('axios');
const res = await axios.post('https://qirim.web.id/api/v1/channels/fetch-messages', {
channel_jid: '120363144123456789@newsletter',
count: 10,
dispatch_webhook: true
}, {
headers: { 'Authorization': 'Bearer ' + process.env.QIRIM_API_KEY }
});
console.log('Total Pesan:', res.data.total);
console.log('Diteruskan ke Webhook:', res.data.dispatched_to_webhook);import requests
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"channel_jid": "120363144123456789@newsletter",
"count": 10,
"dispatch_webhook": True
}
resp = requests.post("https://qirim.web.id/api/v1/channels/fetch-messages", json=payload, headers=headers)
data = resp.json()
print("Total pesan ditarik:", data.get("total", 0)){
"status": true,
"message": "Fetched 3 messages across 1 channel(s)",
"total": 3,
"dispatched_to_webhook": 3,
"data": [
{
"id": "120363144123456789_1728203712",
"channel_jid": "120363144123456789@newsletter",
"channel_name": "KAI Access Channel",
"message": "Informasi Perjalanan: Update Keterlambatan KA 202 per 06 Okt 2026.",
"type": "text",
"timestamp": 1728203712
}
]
}
POST https://qirim.web.id/api/v1/channels/resolve atau GET https://qirim.web.id/api/v1/channels/resolve?url=...
Menerjemahkan tautan undangan saluran publik WhatsApp (contoh: <code>https://whatsapp.com/channel/0029Va...</code>) menjadi JID permanen <code>@newsletter</code>, nama resmi, total pengikut, dan menyimpannya secara otomatis ke database.
# Contoh cURL: Resolve Tautan Saluran
curl -X POST https://qirim.web.id/api/v1/channels/resolve \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://whatsapp.com/channel/0029VaABCD1234efgh"
}'{
"status": true,
"message": "Channel berhasil ditemukan!",
"data": {
"jid": "120363198765432@newsletter",
"name": "KAI Access Official",
"subscribers": 34500,
"desc": "Saluran resmi informasi operasional kereta api PT Kereta Api Indonesia (Persero)."
}
}
POST https://qirim.web.id/api/v1/channels/subscribe
Mendaftarkan socket WhatsApp perangkat untuk menerima event live update real-time langsung dari saluran WhatsApp tersebut.
# Contoh cURL: Subscribe Saluran
curl -X POST https://qirim.web.id/api/v1/channels/subscribe \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channel_jid": "120363198765432@newsletter",
"channel_name": "KAI Access Official"
}'
POST https://qirim.web.id/api/v1/channels/cleanup atau GET https://qirim.web.id/api/v1/channels/cleanup
Memicu pembersihan pesan Saluran WhatsApp dari database yang lebih lama dari 24 jam (atau sesuai parameter older_than_hours). Secara default, pembersihan ini juga berjalan otomatis setiap menit di latar belakang.
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
older_than_hours |
Integer | Opsional | Batas retensi pesan dalam hitungan jam (default: <code>24</code> jam). |
device_id |
Integer / String | Opsional | ID Device WhatsApp spesifik. |
# Contoh cURL: Pembersihan Manual Pesan Saluran >24 Jam
curl -X POST https://qirim.web.id/api/v1/channels/cleanup \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"older_than_hours": 24
}'{
"status": true,
"message": "Berhasil membersihkan 18 pesan saluran WhatsApp yang lebih lama dari 24 jam.",
"retention_hours": 24,
"deleted_message_logs": 18,
"deleted_community_posts": 0
}
Dapatkan daftar seluruh grup yang diikuti nomor Anda via <code>GET /api/v1/wa-groups</code> dan kirimkan pesan ke grup via <code>POST /api/v1/wa-groups/send</code>.
# 1. Ambil Semua Grup WhatsApp Terhubung
curl -X GET "https://qirim.web.id/api/v1/wa-groups?refresh=true" \
-H "Authorization: Bearer YOUR_API_KEY"
# 2. Kirim Pesan / Broadcast ke Grup WhatsApp
curl -X POST https://qirim.web.id/api/v1/wa-groups/send \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"group_jid": "120363028123456789@g.us",
"message": "Halo rekan-rekan grup! Pengingat rapat bulanan hari ini pukul 14:00 WIB."
}'