Lewati ke konten utama
Version: 1.0

Webhook Whatsapp Business

Pengantar

Status pengiriman dan data Inbox dapat diambil dengan menggunakan fitur URL Callback.

Pengaturan URL Callback dapat diatur di menu Account > Account Settings > WhatsApp Business Webhook di app.nusasms.com.

info

URL Callback akan dipanggil dengan metode HTTP POST dengan tipe konten JSON (aplikasi/json).

peringatan

Data callback akan dikirim ke URL callback maksimal 3 kali, jika callback gagal (tidak merespons atau memberikan respons HTTP non 2XX).

Pemanggilan callback juga berhenti setelah menerima respons sukses (dengan kode status HTTP 2XX).

Status Pengiriman Pesan

Status pengiriman adalah untuk perubahan pembaruan status pesan yang dikirim oleh Gateway Anda.

Status yang tersedia:

  • submitted
  • sent
  • delivered
  • read: (jika pengaturan read receipt penerima diaktifkan)
  • failed
info

Callback status pengiriman mungkin dikirim dalam urutan yang tidak teratur. Hal ini biasanya terjadi karena beberapa pembaruan status dikumpulkan dalam waktu penundaan yang sangat singkat di sistem kami. Contoh: read dikirim sebelum delivered

Harap perhatikan urutan urutan status ideal:

  • Sukses: submitted > sent > delivered > read
  • Gagal: failed atau submitted > failed
Contoh data JSON dari _Callback_-nya
{
"type": "status",
"status": {
"message_id": "MESSAGE_ID",
"status": "read",
"timestamp": 1766125960,
"gateway_id": "GATEWAY_ID",
"recipient": "628xxxxxxx"
}
}

Pesan Masul (Inbox)

Setelah pengaturan Webhook Whatsapp Business, anda akan menerima pesan masuk (inbox) yang diterima oleh Gateway anda.

The message payload is the data that has been received by the gateway.

Contoh data JSON dari _request Callback_
{
"type": "inbox",
"inbox": {
"message_id": "MESSAGE_ID",
"timestamp": "1766124507",
"gateway": {
"id": "GATEWAY_ID",
"number": "628xxxxxxx"
},
"sender": {
"number": "628yyyyyyyyy",
"name": "Nama Akun Whatsapp Sender"
},
"message": {
"type": "text",
"text": {
"body": "Teks inbox"
}
}
}
}

Contoh Kode Webhook-nya

peringatan

Contoh kode di bawah berfungsi sebagai referensi, bukan layanan pengambilan data webhook yang lengkap. Gunakan mereka sebagai dasar untuk memperluas dan menyesuaikan sesuai kebutuhan spesifik Anda.

Golang

Ini adalah contoh aplikasi web Golang sederhana untuk mengambil data webhook menggunakan net/http.

package main

import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"time"
)

// Gateway represents the gateway information in the inbox payload
type Gateway struct {
ID string `json:"id"`
Number string `json:"number"`
}

// Sender represents the sender information in the inbox payload
type Sender struct {
Number string `json:"number"`
Name string `json:"name"`
}

// MessageText represents the text message content
type MessageText struct {
Body string `json:"body"`
}

// Message represents the message details in the inbox payload
type Message struct {
Type string `json:"type"`
Text MessageText `json:"text,omitempty"`
}

// Status represents the nested status object in the status payload
type Status struct {
MessageID string `json:"message_id"`
Status string `json:"status"`
Timestamp string `json:"timestamp"`
GatewayID string `json:"gateway_id,omitempty"`
Gateway *Gateway `json:"gateway,omitempty"`
Recipient string `json:"recipient,omitempty"`
}

// Inbox represents the inbox payload structure
type Inbox struct {
MessageID string `json:"message_id"`
Timestamp string `json:"timestamp"`
Gateway Gateway `json:"gateway"`
Sender Sender `json:"sender"`
Message Message `json:"message"`
}

// WebhookPayload represents the full JSON structure
type WebhookPayload struct {
Type string `json:"type"`
Status *Status `json:"status,omitempty"`
Inbox *Inbox `json:"inbox,omitempty"`
}

func handleWebhook(w http.ResponseWriter, r *http.Request) {
// Ensure only POST requests are accepted
if r.Method != http.MethodPost {
http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)
return
}

// Limit request body size to prevent potential DoS
r.Body = http.MaxBytesReader(w, r.Body, 1048576) // 1MB max

// Read the request body
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error reading request body", http.StatusBadRequest)
return
}
defer r.Body.Close()

// Parse the JSON
var payload WebhookPayload
err = json.Unmarshal(body, &payload)
if err != nil {
http.Error(w, fmt.Sprintf("Error parsing JSON: %v", err), http.StatusBadRequest)
return
}

// Process the webhook based on type
processWebhook(payload)

// Respond with success
w.WriteHeader(http.StatusOK)
w.Write([]byte("Webhook received successfully"))
}

func processWebhook(payload WebhookPayload) {
fmt.Printf("Received Webhook Type: %s\n", payload.Type)

switch payload.Type {
case "status":
processStatusWebhook(payload.Status)
case "inbox":
processInboxWebhook(payload.Inbox)
default:
fmt.Printf("Unknown webhook type: %s\n", payload.Type)
}
}

func processStatusWebhook(status *Status) {
// Process the data
return nil
}

func processInboxWebhook(inbox *Inbox) {
// Process the data
return nil
}

func main() {
// Set up routes
http.HandleFunc("/webhook", handleWebhook)

// Start the server
port := 8080
fmt.Printf("Server starting on port %d...\n", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
}

PHP

header('Content-Type: application/json');

// Read raw POST body
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);

if (json_last_error() !== JSON_ERROR_NONE) {
http_response_code(400);
echo json_encode(['error' => 'Invalid JSON']);
exit;
}

// Helper to send a JSON response
function respond(array $payload, int $code = 200): void
{
http_response_code($code);
echo json_encode($payload);
exit;
}

// Status payload
if (isset($data['type']) && $data['type'] === 'status' && isset($data['status'])) {
$status = $data['status'];

// Basic validation (you can expand as needed)
$required = ['message_id', 'status', 'timestamp', 'gateway_id', 'recipient'];
foreach ($required as $field) {
if (!isset($status[$field])) {
respond(['error' => "Missing field $field in status payload"], 400);
}
}

// Process the data here

respond(['result' => 'status processed']);
}

// Inbox payload
if (isset($data['type']) && $data['type'] === 'inbox' && isset($data['inbox'])) {
$inbox = $data['inbox'];

// Required top‑level fields
$requiredTop = ['message_id', 'timestamp', 'gateway', 'sender', 'message'];
foreach ($requiredTop as $field) {
if (!isset($inbox[$field])) {
respond(['error' => "Missing field $field in inbox payload"], 400);
}
}

// Process the data here

respond(['result' => 'inbox processed']);
}

// -----------------------------------------------------------------
// If we reach here, the payload type is unsupported
// -----------------------------------------------------------------
respond(['error' => 'Unsupported payload type'], 400);
?>

Python

Berikut adalah contoh aplikasi web Rest API sederhana menggunakan Python FastAPI

app.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from typing import Literal, Union

app = FastAPI()


class Payload(BaseModel):
type: Literal["inbox", "status"]
inbox: dict | None = None
status: dict | None = None


# ---------- Endpoints ----------
@app.post("/webhook")
async def receive_payload(payload: Payload):
"""
Accepts either a `status` or an `inbox` payload.
"""
if payload.type == 'inbox':
# Process the webhook data here
return {"result": "inbox processed"}
elif payload.type == 'status'
# Process the webhook data here
return {"result": "status processed"}
raise HTTPException(status_code=400, detail="Unsupported payload type")