Skip to content

Kirim template

Kirim template yang udah di-approve — buat update pesanan, OTP, dan pengingat.

Updated View as Markdown

Pakai template kalau kamu yang mau nge-chat duluan — update pesanan, kode OTP, pengingat janji — apalagi kalau udah lewat 24 jam sejak chat terakhir pelanggan. Semua template harus di-approve Meta dulu ya.

Nge-kirim template butuh lebih dari sekadar nama dan bahasa. Kamu harus ngisi components yang sesuai sama struktur template-nya: variabel body, header (bisa gambar atau teks), dan parameter tombol kalau template-nya punya tombol dengan link dinamis.

Sebelum ngirim

Bikin dan tunggu template di-approve

Bikin template di aplikasi Wazapin atau sync dari Meta kalau pakai channel official. Pastikan statusnya udah approved dulu baru bisa dipakai.

Cek daftar template kamu pakai GET /v1/templates. Cek juga dukungan channel buat bedanya perilaku official vs unofficial.

Cek struktur template-nya

Buka template di dashboard dan catat bagian-bagiannya:

  • Header — bisa kosong, teks ({{1}}), gambar, video, atau dokumen
  • Body — teks dengan placeholder {{1}}, {{2}}, …
  • Tombol — quick reply, URL (bisa ada {{1}} di link-nya), copy code, dll.

Array components yang kamu kirim harus ngikutin urutan bagian ini persis.

Susun array components

Tiap bagian jadi satu object di content.template.components:

type di components Kapan dipakai
header Kalau template punya header dinamis (teks, gambar, video, dokumen)
body Kalau body template ada variabel {{n}}
button Kalau ada tombol URL atau tombol dinamis lain (sub_type, index)

Nggak ada variabel di bagian itu? Skip aja — nggak perlu dikirim.

Format request

Semua kirim template pakai POST /v1/messages dengan type: "template" dan object content.template di dalamnya (formatnya kompatibel sama Meta).

Field Wajib? Deskripsi
channel_id Ya Channel WhatsApp yang udah terhubung
to Ya Nomor tujuan format internasional
type Ya template
content.template.name Ya Nama template yang udah di-approve
content.template.language.code Ya Kode bahasa, mis. en_US, id
content.template.components Sering iya Parameter buat header / body / button

Contoh: cuma variabel body

Isi body template: Hi {{1}}, your order {{2}} is on the way.

curl -X POST "https://api.wazapin.com/v1/messages" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel_id": "wzp_abc123",
    "to": "6281234567890",
    "type": "template",
    "content": {
      "template": {
        "name": "order_shipped",
        "language": { "code": "en_US" },
        "components": [
          {
            "type": "body",
            "parameters": [
              { "type": "text", "text": "John" },
              { "type": "text", "text": "ORD-42" }
            ]
          }
        ]
      }
    }
  }'
import { WazapinClient, templateMessage } from "@wazapin/sdk";

const wazapin = new WazapinClient({ apiKey: process.env.WAZAPIN_API_KEY! });

const { data: message } = await wazapin.messages.send(
  templateMessage({
    channel_id: "wzp_abc123",
    to: "6281234567890",
    name: "order_shipped",
    language: "en_US",
    components: [
      {
        type: "body",
        parameters: [
          { type: "text", text: "John" },
          { type: "text", text: "ORD-42" },
        ],
      },
    ],
  }),
);

console.log(message.id);
import requests

response = requests.post(
    "https://api.wazapin.com/v1/messages",
    headers={"X-Api-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
    json={
        "channel_id": "wzp_abc123",
        "to": "6281234567890",
        "type": "template",
        "content": {
            "template": {
                "name": "order_shipped",
                "language": {"code": "en_US"},
                "components": [
                    {
                        "type": "body",
                        "parameters": [
                            {"type": "text", "text": "John"},
                            {"type": "text", "text": "ORD-42"},
                        ],
                    }
                ],
            }
        },
    },
    timeout=30,
)
response.raise_for_status()
print(response.json())
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	body := []byte(`{
  "channel_id": "wzp_abc123",
  "to": "6281234567890",
  "type": "template",
  "content": {
    "template": {
      "name": "order_shipped",
      "language": {
        "code": "en_US"
      },
      "components": [
        {
          "type": "body",
          "parameters": [
            {
              "type": "text",
              "text": "John"
            },
            {
              "type": "text",
              "text": "ORD-42"
            }
          ]
        }
      ]
    }
  }
}`)

	req, err := http.NewRequest(http.MethodPost, "https://api.wazapin.com/v1/messages", bytes.NewReader(body))
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-Api-Key", os.Getenv("WAZAPIN_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	// 201 = message accepted; delivery status via webhooks / GET /v1/messages/{id}
	out, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.StatusCode, string(out))
}
<?php

$payload = '{
  "channel_id": "wzp_abc123",
  "to": "6281234567890",
  "type": "template",
  "content": {
    "template": {
      "name": "order_shipped",
      "language": {
        "code": "en_US"
      },
      "components": [
        {
          "type": "body",
          "parameters": [
            {
              "type": "text",
              "text": "John"
            },
            {
              "type": "text",
              "text": "ORD-42"
            }
          ]
        }
      ]
    }
  }
}';

$ch = curl_init("https://api.wazapin.com/v1/messages");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Content-Type: application/json",
    "X-Api-Key: " . getenv("WAZAPIN_API_KEY"),
]);

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

// 201 = message accepted; delivery status via webhooks / GET /v1/messages/{id}
echo $httpCode . "\n" . $response . "\n";
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class SendMessage {
    public static void main(String[] args) throws Exception {
        String body = """
                {"channel_id": "wzp_abc123", "to": "6281234567890", "type": "template", "content": {"template": {"name": "order_shipped", "language": {"code": "en_US"}, "components": [{"type": "body", "parameters": [{"type": "text", "text": "John"}, {"type": "text", "text": "ORD-42"}]}]}}}
                """;

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.wazapin.com/v1/messages"))
                .header("X-Api-Key", System.getenv("WAZAPIN_API_KEY"))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(body))
                .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
                .send(request, HttpResponse.BodyHandlers.ofString());

        // 201 = message accepted; delivery status via webhooks / GET /v1/messages/{id}
        System.out.println(response.statusCode());
        System.out.println(response.body());
    }
}
require "net/http"
require "uri"

uri = URI("https://api.wazapin.com/v1/messages")
request = Net::HTTP::Post.new(uri)
request["Content-Type"] = "application/json"
request["X-Api-Key"] = ENV["WAZAPIN_API_KEY"]
request.body = '{"channel_id": "wzp_abc123", "to": "6281234567890", "type": "template", "content": {"template": {"name": "order_shipped", "language": {"code": "en_US"}, "components": [{"type": "body", "parameters": [{"type": "text", "text": "John"}, {"type": "text", "text": "ORD-42"}]}]}}}'

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

# 201 = message accepted; delivery status via webhooks / GET /v1/messages/{id}
puts response.code
puts response.body
using System.Net.Http;
using System.Text;

var body = "{\"channel_id\": \"wzp_abc123\", \"to\": \"6281234567890\", \"type\": \"template\", \"content\": {\"template\": {\"name\": \"order_shipped\", \"language\": {\"code\": \"en_US\"}, \"components\": [{\"type\": \"body\", \"parameters\": [{\"type\": \"text\", \"text\": \"John\"}, {\"type\": \"text\", \"text\": \"ORD-42\"}]}]}}}";

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Api-Key", Environment.GetEnvironmentVariable("WAZAPIN_API_KEY"));

var response = await client.PostAsync(
    "https://api.wazapin.com/v1/messages",
    new StringContent(body, Encoding.UTF8, "application/json"));

// 201 = message accepted; delivery status via webhooks / GET /v1/messages/{id}
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());

Contoh: header gambar + body

Template dengan header gambar dan satu variabel body.

{
  "channel_id": "wzp_abc123",
  "to": "6281234567890",
  "type": "template",
  "content": {
    "template": {
      "name": "promo_with_image",
      "language": { "code": "id" },
      "components": [
        {
          "type": "header",
          "parameters": [
            {
              "type": "image",
              "image": { "link": "https://cdn.example.com/promo.jpg" }
            }
          ]
        },
        {
          "type": "body",
          "parameters": [
            { "type": "text", "text": "Ramadan Sale" }
          ]
        }
      ]
    }
  }
}

Contoh: header teks dinamis

Header template-nya: Hello {{1}} — tinggal kirim header component di dalam content.template.components:

{
  "channel_id": "wzp_abc123",
  "to": "6281234567890",
  "type": "template",
  "content": {
    "template": {
      "name": "greeting_header",
      "language": { "code": "en_US" },
      "components": [
        {
          "type": "header",
          "parameters": [
            { "type": "text", "text": "John" }
          ]
        },
        {
          "type": "body",
          "parameters": [
            { "type": "text", "text": "Your appointment is confirmed." }
          ]
        }
      ]
    }
  }
}

Contoh: tombol URL dinamis

Template dengan tombol URL yang ada {{1}} di link-nya — component button tinggal taruh di array components yang sama:

{
  "channel_id": "wzp_abc123",
  "to": "6281234567890",
  "type": "template",
  "content": {
    "template": {
      "name": "order_tracking",
      "language": { "code": "en_US" },
      "components": [
        {
          "type": "body",
          "parameters": [
            { "type": "text", "text": "John" },
            { "type": "text", "text": "ORD-42" }
          ]
        },
        {
          "type": "button",
          "sub_type": "url",
          "index": "0",
          "parameters": [
            { "type": "text", "text": "ORD-42" }
          ]
        }
      ]
    }
  }
}

index itu urutan tombol di template (mulai dari 0). sub_type harus sama kayak yang di-approve Meta — url, quick_reply, copy_code, dll.

Mau lihat daftar template atau sync dari Meta? Pakai wazapin.templates.list() dan wazapin.templates.sync(). Detail lengkapnya di SDK template.

Kesalahan yang sering kejadian

Kejadiannya Beresinnya gimana
Template belum di-approve Tunggu Meta approve dulu, atau pakai template lain yang udah approved
Salah language.code Harus persis sama kayak locale template-nya (en_US bukan en)
components kurang Isi semua {{n}} yang ada di header / body / tombol — jangan ada yang kelewat
Pakai template_name datar di content Harus pakai content.template.name yang nested
URL gambar header bukan HTTPS Pakai URL HTTPS publik yang bisa diakses Meta

Terkait

Endpoint

POST https://api.wazapin.com/v1/messages

Authenticate with X-Api-Key. See Authentication.

Response

On success, the API returns 201 Created with a lean accept-response (status often starts as queued).

{
  "id": "9f1fd66d-c37a-4b50-a8c2-b4dca523f9c8",
  "status": "queued",
  "channel_id": "wzp_abc123",
  "to": "6281234567890",
  "created_at": "2026-03-04T06:20:10Z"
}

Track delivery with Webhooks or GET /v1/messages/{messageID} (full record, including provider_message_id once the provider acknowledges it).

Navigation

Type to search…

↑↓ navigate↵ selectEsc close