Logo

KTWA - WhatsApp Gateway

Meta Cloud API Developer Hub
Admin Login

Dokumentasi resmi pengiriman WhatsApp Template disetujui Meta (`APPROVED`) & Callback Receiver untuk Pihak Ketiga (Third-Party Developers).

Ketentuan Resmi Meta Cloud API (Outbound Messages)

1. Ringkasan API

REST API **KTWA - WhatsApp Gateway** menggunakan protokol HTTP/HTTPS standar dengan format payload JSON yang meneruskan pesan secara real-time ke Meta Cloud API.

BASE API URL:
https://ktwa.kurniahost.biz.id/api/v1/

2. Header & Otentikasi

Setiap request dari Pihak Ketiga wajib menyertakan 3 HTTP Header berikut:

Header Name Type Keterangan
Content-Type string Harus diisi: application/json
X-API-Key string API Key publik milik Client API Anda.
X-API-Secret string API Secret rahasia milik Client API Anda.
Content-Type: application/json
X-API-Key: YOUR_API_KEY_HERE
X-API-Secret: YOUR_API_SECRET_HERE

3. Endpoint REST API

Wajib digunakan untuk notifikasi transaksi/pesan pertama ke pelanggan (Template disetujui Meta).

REQUEST JSON:
{
  "phone": "6281234567890",
  "template_name": "order_confirmation",
  "language": "id",
  "components": [
    {
      "type": "body",
      "parameters": [
        { "type": "text", "text": "Budi Santoso" },
        { "type": "text", "text": "INV-2026-001" },
        { "type": "text", "text": "Rp 150.000" }
      ]
    }
  ]
}
RESPONSE SUCCESS (200 OK):
{
  "success": true,
  "data": {
    "id": 1052,
    "wa_message_id": "wamid.HBgLNjgxMjM0...",
    "recipient": "6281234567890",
    "status": "sent"
  },
  "message": "Pesan berhasil dikirim ke Meta API"
}

Hanya berlaku dalam rentang 24 jam setelah pelanggan membalas pesan Anda.

REQUEST JSON:
{
  "phone": "6281234567890",
  "message": "Terima kasih telah menghubungi CS kami."
}
REQUEST JSON:
{
  "phone": "6281234567890",
  "document_url": "https://example.com/invoice-1001.pdf",
  "filename": "Invoice_1001.pdf",
  "caption": "Terlampir invoice transaksi Anda."
}
RESPONSE SUCCESS (200 OK):
{
  "success": true,
  "data": {
    "id": 1052,
    "wa_message_id": "wamid.HBgLNjgxMjM0...",
    "recipient": "6281234567890",
    "status": "read"
  },
  "message": "Detail pesan berhasil diambil"
}

4. Contoh Kode Integrasi (Outbound Template)

<?php
$apiUrl = 'https://ktwa.kurniahost.biz.id/api/v1/send/template';
$apiKey = 'YOUR_API_KEY_HERE';
$apiSecret = 'YOUR_API_SECRET_HERE';

$payload = [
    'phone' => '6281234567890',
    'template_name' => 'order_confirmation', // Wajib disetujui Meta
    'language' => 'id',
    'components' => [
        [
            'type' => 'body',
            'parameters' => [
                ['type' => 'text', 'text' => 'Budi Santoso'],
                ['type' => 'text', 'text' => 'INV-2026-001'],
                ['type' => 'text', 'text' => 'Rp 150.000']
            ]
        ]
    ]
];

$ch = curl_init($apiUrl);
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'X-API-Key: ' . $apiKey,
        'X-API-Secret: ' . $apiSecret,
    ],
    CURLOPT_POSTFIELDS => json_encode($payload)
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$result = json_decode($response, true);
print_r($result);
?>
<?php
use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'https://ktwa.kurniahost.biz.id/api/v1/',
    'headers' => [
        'Content-Type' => 'application/json',
        'X-API-Key' => 'YOUR_API_KEY_HERE',
        'X-API-Secret' => 'YOUR_API_SECRET_HERE',
    ]
]);

$response = $client->post('send/template', [
    'json' => [
        'phone' => '6281234567890',
        'template_name' => 'payment_receipt',
        'language' => 'id',
        'components' => [
            [
                'type' => 'body',
                'parameters' => [
                    ['type' => 'text', 'text' => 'Ahmad Sujadi'],
                    ['type' => 'text', 'text' => 'LUNAS']
                ]
            ]
        ]
    ]
]);

$data = json_decode($response->getBody(), true);
print_r($data);
?>
const API_URL = 'https://ktwa.kurniahost.biz.id/api/v1/send/template';
const API_KEY = 'YOUR_API_KEY_HERE';
const API_SECRET = 'YOUR_API_SECRET_HERE';

async function sendWhatsAppTemplate(phone, name, invoiceNo) {
  try {
    const res = await fetch(API_URL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': API_KEY,
        'X-API-Secret': API_SECRET
      },
      body: JSON.stringify({
        phone: phone,
        template_name: 'order_confirmation',
        language: 'id',
        components: [
          {
            type: 'body',
            parameters: [
              { type: 'text', text: name },
              { type: 'text', text: invoiceNo }
            ]
          }
        ]
      })
    });

    const data = await res.json();
    console.log('Response:', data);
  } catch (err) {
    console.error('Error:', err);
  }
}

sendWhatsAppTemplate('6281234567890', 'Budi Santoso', 'INV-2026-001');
const axios = require('axios');

const waApi = axios.create({
  baseURL: 'https://ktwa.kurniahost.biz.id/api/v1/',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': 'YOUR_API_KEY_HERE',
    'X-API-Secret': 'YOUR_API_SECRET_HERE'
  }
});

async function sendOtp(phone, code) {
  const res = await waApi.post('send/template', {
    phone: phone,
    template_name: 'otp_verification',
    language: 'id',
    components: [
      {
        type: 'body',
        parameters: [{ type: 'text', text: code }]
      }
    ]
  });
  console.log(res.data);
}

sendOtp('6281234567890', '849201');

5. Receiver Webhook Status Callback

KTWA Gateway akan mengirimkan callback `POST` JSON saat status pengiriman template berubah (*sent*, *delivered*, *read*, *failed*).

PAYLOAD CALLBACK JSON:
{
  "event": "message_status",
  "data": {
    "message_id": 1052,
    "wa_message_id": "wamid.HBgLNjgxMjM0...",
    "recipient": "6281234567890",
    "status": "delivered",
    "timestamp": "2026-07-26 08:30:00",
    "error_code": null,
    "error_message": null
  }
}
PHP Callback Script:
<?php
$json = file_get_contents('php://input');
$payload = json_decode($json, true);

if ($payload && isset($payload['event']) && $payload['event'] === 'message_status') {
    $data = $payload['data'];
    $status = $data['status'];

    // Update status di database internal Anda:
    // updateDatabase($data['wa_message_id'], $status);

    http_response_code(200);
    echo json_encode(['status' => 'OK']);
    exit;
}
?>
Node.js Express Callback:
app.post('/api/wa-callback', (req, res) => {
  const { event, data } = req.body;
  if (event === 'message_status') {
    console.log(`Status ${data.recipient}: ${data.status}`);
    return res.status(200).json({ status: 'OK' });
  }
  res.status(400).end();
});

6. HTTP Status & Meta Error Codes

HTTP Status Error Message Penjelasan & Solusi
400 Meta API error Template belum disetujui Meta (`APPROVED`) atau jumlah parameter `components` tidak cocok dengan template.
401 API Key dan Secret diperlukan Periksa apakah header X-API-Key dan X-API-Secret sudah dikirimkan dengan benar.
422 Parameter "phone" dan "template_name" wajib diisi Payload JSON kurang atau nomor tujuan tidak menggunakan format 628xxx.
429 Rate limit exceeded Jumlah request melebihi limit per menit yang ditentukan.
503 Akun WhatsApp tidak aktif Nomor WhatsApp pengirim pada akun Anda sedang non-aktif.