Ana içeriğe geç

Toplu Şablon Mesaj API Dokümantasyonu

Bu API, WhatsApp kanalı üzerinden birden fazla alıcıya aynı anda şablon mesajı (template message) göndermenizi sağlar. Gönderim işlemi asenkron olarak gerçekleşir; API isteği anında bir bulkMessageId döner ve mesajlar arka planda kuyruğa alınarak işlenir.

POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/send.js

Temel Özellikler

  • Tek istek ile 1–5.000 alıcıya toplu şablon mesajı gönderimi
  • Her alıcı için kişiselleştirilmiş değişkenler (HEADER, BODY, BUTTONS, CAROUSEL)
  • Tüm alıcılar için ortak defaultPayload + kişiye özel payload birleştirme (isMerge)
  • Zamanlanmış gönderim (scheduleAt)
  • Alıcıları username (telefon numarası), userId veya sessionId ile belirtme
  • Gönderim sonrası konuşmaları otomatik kullanıcı veya çalışma grubuna atama (action)
uyarı

Bu API yalnızca Meta tarafından onaylanmış şablonları gönderebilir. Şablon adı ve dil kodu, Meta Business Manager'daki şablon kaydı ile tam olarak eşleşmelidir.

İstek Parametreleri

Üst Seviye Parametreler

ParametreTipZorunluAçıklama
channelUsernamestringEvetMesajın gönderileceği WhatsApp kanal numarası (örn. "908506669933")
connectorBrandstringEvetKanal bağlayıcı markası. Şu an desteklenen değer: "whatsapp"
titlestringHayırKampanya başlığı. Dashboard'da görüntüleme için kullanılır. Varsayılan: "-"
scheduleAtstring (ISO 8601)HayırZamanlanmış gönderim tarihi ve saati (örn. "2026-06-10T10:00:00.000Z"). Belirtilmezse hemen gönderilir.
defaultPayloadobjectKoşullu*Tüm alıcılara uygulanacak varsayılan şablon payload'ı. Kendi payload'u olmayan alıcılar için zorunludur.
recipientsarrayEvetAlıcı listesi. Minimum 1, maksimum 5.000 alıcı. Her alıcı benzersiz olmalıdır.
actionobjectHayırGönderim sonrası konuşmaya uygulanacak aksiyon. assign-to-user veya assign-to-workgroup

*Her alıcının kendi payload'u varsa defaultPayload opsiyoneldir.

Alıcı (Recipient) Yapısı

Her alıcı için username, userId ve sessionId alanlarından yalnızca biri verilmelidir. Birden fazlası aynı anda kullanılamaz; hiçbiri verilmezse istek hata döner.

AlanTipAçıklama
usernamestringAlıcının telefon numarası (örn. "905554443322"). Kullanıcı sistemde yoksa otomatik oluşturulur.
userIdstringSistemdeki mevcut kullanıcının ID'si
sessionIdstringSistemdeki mevcut konuşma oturumunun ID'si
payloadobjectBu alıcıya özel şablon payload'ı (opsiyonel). isMerge: true ise defaultPayload ile birleştirilir.
isMergebooleanBu alıcı için birleştirme davranışını geçersiz kılar (opsiyonel). Belirtilmezse defaultPayload.isMerge değeri kullanılır.

Action Yapısı

AlanTipAçıklama
action.keystring"assign-to-user" — konuşmayı belirli bir agent'a atar; "assign-to-workgroup" — konuşmayı çalışma grubuna atar
action.valuestringAtanacak kullanıcı veya çalışma grubunun ID'si

Template Payload Yapısı

defaultPayload ve alıcıya özel payload aynı yapıyı paylaşır. Template türü için type: "template" belirtilmelidir.

{
"type": "template",
"template": {
"templateName": "order_confirmation", // zorunlu (defaultPayload'da)
"languageCode": "tr-TR", // opsiyonel — örn. "tr", "en", "tr-TR", "en-US"
"variables": [ ... ] // opsiyonel
},
"isMerge": true // opsiyonel
}
AlanTipZorunluAçıklama
typestringEvetPayload türü. Template için: "template"
template.templateNamestringEvet*Meta'da kayıtlı şablon adı. isMerge: true kullanılıyorsa alıcı payload'unda opsiyoneldir (default'tan devralınır).
template.languageCodestringHayırŞablon dil kodu (örn. "tr", "en", "tr-TR", "en-US"). Şablonun Meta'da kayıtlı dil kodu ile tam olarak eşleşmelidir.
template.variablesarrayHayırŞablon bileşenlerine uygulanacak değişken listesi. Aşağıda detaylı açıklanmaktadır.
isMergebooleanHayırtrue: Alıcı payload'u defaultPayload ile derin birleştirme (deep merge) yapılır. false/belirtilmezse: Alıcı payload'u defaultPayload'un yerine tamamen geçer.
isMerge Davranışı
  • defaultPayload.isMerge: true + alıcının kendi payload'u varsa → deep merge uygulanır
  • Deep merge ile alıcı yalnızca variables sağlayabilir, templateName ve languageCode default'tan gelir
  • Alıcının isMerge alanı, defaultPayload.isMerge değerini geçersiz kılar
  • Alıcının kendi payload'u yoksa her zaman defaultPayload kullanılır

Variables Yapısı

variables dizisinin her elemanı bir şablon bileşenine karşılık gelir. Bir bileşen türü (type) dizide yalnızca bir kez yer almalıdır.

typeAçıklamaparameterscards
"HEADER"Şablon başlık bileşeni. Metin değişkeni veya medya URL'si (resim, video, doküman)Evet
"BODY"Şablon gövde metni değişkenleriEvet
"BUTTONS"Dinamik URL suffix içeren buton değişkenleriEvet
"CAROUSEL"Carousel şablonu kart bileşenleriEvet

Parameters Formatları

parameters alanı üç farklı formatta verilebilir:

// Format 1: Dizi (index tabanlı) — {{1}}, {{2}}, {{3}} gibi placeholder'lar için
"parameters": ["değer1", "değer2", "değer3"]

// Format 2: Nesne (sayısal anahtar) — {{1}}, {{2}} için alternatif gösterim
"parameters": { "1": "değer1", "2": "değer2" }

// Format 3: Nesne (isim tabanlı) — {{ad}}, {{tutar}} gibi adlandırılmış placeholder'lar için
"parameters": { "ad": "Ahmet", "tutar": "150 TL" }
Hangi format ne zaman kullanılır?
  • Meta şablon editöründe {{1}}, {{2}} gibi placeholder oluşturduysa → dizi veya sayısal nesne formatı kullanın
  • Şablonda {{firstName}}, {{orderTotal}} gibi isimli placeholder'lar varsa → isim tabanlı nesne formatı kullanın
  • Dizi kullanıldığında sıralama önemlidir: ilk eleman {{1}}'e, ikinci eleman {{2}}'ye karşılık gelir

HEADER Bileşeni

Şablon başlığında medya (resim, video, doküman) veya dinamik metin varsa HEADER bileşeni kullanılır.

// Medya header (resim URL)
{
"type": "HEADER",
"parameters": ["https://example.com/product-image.jpg"]
}

// Metin header değişkeni
{
"type": "HEADER",
"parameters": ["Özel Kampanya"]
}

BODY Bileşeni

Şablon gövdesindeki dinamik metin değişkenleri için kullanılır.

// Dizi formatı — şablonda {{1}}, {{2}}, {{3}} kullanıldıysa
{
"type": "BODY",
"parameters": ["Ahmet", "ORD-12345", "150,00 TL"]
}

// İsim tabanlı — şablonda {{ad}}, {{siparisTutari}} kullanıldıysa
{
"type": "BODY",
"parameters": {
"ad": "Ahmet",
"siparisTutari": "150,00 TL"
}
}

BUTTONS Bileşeni

Dinamik URL suffix içeren butonlar için kullanılır. Şablonda birden fazla URL butonu varsa, değişkeni olan butonlar sırasıyla indekslenir (değişkeni olmayan veya FLOW tipi butonlar sayılmaz).

// Tek URL buton suffix değişkeni
{
"type": "BUTTONS",
"parameters": ["takip/ORD-12345"]
}

// Birden fazla URL buton suffix değişkeni (sırayla ilk, ikinci URL butonu)
{
"type": "BUTTONS",
"parameters": ["takip/ORD-12345", "iptal/ORD-12345"]
}

Carousel şablonlarında her kart için ayrı bileşen değişkenleri tanımlanır.

{
"type": "CAROUSEL",
"cards": [
{
"components": [
{
"type": "HEADER",
"parameters": ["https://example.com/card1.jpg"]
},
{
"type": "BODY",
"parameters": ["Ürün A", "99,00 TL"]
}
]
},
{
"components": [
{
"type": "HEADER",
"parameters": ["https://example.com/card2.jpg"]
},
{
"type": "BODY",
"parameters": ["Ürün B", "149,00 TL"]
}
]
}
]
}
uyarı

cards dizisinin uzunluğu şablondaki kart sayısıyla tam olarak eşleşmelidir.


Örnekler

1. Basit Şablon — Değişkensiz, Tüm Alıcılara Aynı

Değişken içermeyen, sabit içerikli bir şablonu birden fazla kişiye göndermek için en sade kullanım şeklidir.

{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "Genel Duyuru",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "hello_world",
"languageCode": "tr-TR"
}
},
"recipients": [{ "username": "905554443301" }, { "username": "905554443302" }, { "username": "905554443303" }]
}
curl --location 'https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/send.js' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_TOKEN' \
--data '{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "Genel Duyuru",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "hello_world",
"languageCode": "tr-TR"
}
},
"recipients": [
{ "username": "905554443301" },
{ "username": "905554443302" },
{ "username": "905554443303" }
]
}'
ipucu
  • username ile belirtilen alıcılar sistemde yoksa otomatik olarak oluşturulur
  • Tüm alıcılar aynı defaultPayload'u kullanır, alıcıya özel ek veri gerekmez
  • isMerge belirtilmediğinde her alıcı doğrudan defaultPayload'u kullanır

2. Ortak Body Değişkenli Şablon

Tüm alıcılara aynı değişken değerleriyle bir şablon gönderilir. Şablonda {{1}}, {{2}} gibi placeholder'lar bulunmaktadır.

{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "Yaz Kampanyası",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "promo_notification",
"languageCode": "tr-TR",
"variables": [
{
"type": "BODY",
"parameters": ["30", "31 Temmuz 2026"]
}
]
}
},
"recipients": [{ "username": "905554443301" }, { "username": "905554443302" }]
}
ipucu
  • Bu örnekte şablon body'si şu içeriğe sahip olabilir: "Kampanyamızda {{1}} indirim fırsatı sizi bekliyor! Son tarih: {{2}}"
  • parameters[0]{{1}} yerine, parameters[1]{{2}} yerine geçer

3. Kişiselleştirilmiş Şablon — isMerge ile Per-Recipient Değişkenler

Her alıcı için farklı değişkenler kullanılır. defaultPayload'da isMerge: true ayarlanarak alıcıların yalnızca variables sağlaması yeterli olur; templateName ve languageCode default'tan devralınır.

Bu örnekte şablonun hem medya header'ı hem de kişiselleştirilmiş body değişkenleri bulunmaktadır.

{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "Kişisel Sipariş Bildirimi",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "order_confirmation",
"languageCode": "tr-TR"
},
"isMerge": true
},
"recipients": [
{
"username": "905554443301",
"payload": {
"template": {
"variables": [
{
"type": "HEADER",
"parameters": ["https://s3.example.com/product-a.jpg"]
},
{
"type": "BODY",
"parameters": ["Ahmet", "ORD-001", "150,00 TL"]
}
]
}
}
},
{
"username": "905554443302",
"payload": {
"template": {
"variables": [
{
"type": "HEADER",
"parameters": ["https://s3.example.com/product-b.jpg"]
},
{
"type": "BODY",
"parameters": ["Fatma", "ORD-002", "289,00 TL"]
}
]
}
}
}
]
}
ipucu
  • isMerge: true sayesinde alıcı payload'unda templateName tekrar yazılmak zorunda değildir
  • Her alıcının variables dizisi birbirinden tamamen bağımsızdır
  • Header medya URL'si herkese açık (publicly accessible) bir URL olmalıdır
  • Alıcı payload'unda type belirtilmediğinde defaultPayload.type devralınır

4. URL Buton Değişkeni

Şablonda dinamik URL suffix içeren bir buton varsa BUTTONS bileşeni kullanılır. Örneğin https://example.com/track/ base URL'sine eklenen sipariş takip numarası.

{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "Kargo Takip Bildirimi",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "shipment_tracking",
"languageCode": "tr-TR"
},
"isMerge": true
},
"recipients": [
{
"username": "905554443301",
"payload": {
"template": {
"variables": [
{
"type": "BODY",
"parameters": ["Ahmet", "TK-98765"]
},
{
"type": "BUTTONS",
"parameters": ["TK-98765"]
}
]
}
}
},
{
"username": "905554443302",
"payload": {
"template": {
"variables": [
{
"type": "BODY",
"parameters": ["Recep", "TK-12345"]
},
{
"type": "BUTTONS",
"parameters": ["TK-12345"]
}
]
}
}
}
]
}
ipucu
  • BUTTONS parametreleri, değişkeni olan butonların sırasına göre eşleştirilir
  • FLOW tipi butonlar ve değişkeni olmayan butonlar sayılmaz; sıralama yalnızca dinamik URL butonlarını kapsar
  • Şablon butonu https://example.com/track/{{1}} ise, parameters[0]{{1}} yerine geçer

5. Zamanlanmış Gönderim

İleri bir tarih ve saat için gönderim planlanır. scheduleAt ISO 8601 formatında UTC zaman damgasıdır.

{
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"title": "Sabah Kampanya Mesajı",
"scheduleAt": "2026-06-10T07:00:00.000Z",
"defaultPayload": {
"type": "template",
"template": {
"templateName": "morning_campaign",
"languageCode": "en-US"
},
"isMerge": true
},
"action": {
"key": "assign-to-workgroup",
"value": "WORKGROUP_ID"
},
"recipients": [
{
"username": "905554443301",
"payload": {
"template": {
"variables": [
{
"type": "BODY",
"parameters": { "ad": "Ahmet", "indirimOrani": "25" }
}
]
}
}
},
{
"username": "905554443302",
"payload": {
"template": {
"variables": [
{
"type": "BODY",
"parameters": { "ad": "Zeynep", "indirimOrani": "40" }
}
]
}
}
}
]
}
ipucu
  • scheduleAt UTC zaman diliminde verilmelidir (örn. Türkiye saati 10:00 için 07:00:00.000Z)
  • Bu örnekte isim tabanlı parametre formatı kullanılmıştır: şablonda {{ad}} ve {{indirimOrani}} gibi placeholder'lar olmalıdır
  • action ile mesaj gönderilen konuşmalar belirlenen çalışma grubuna otomatik atanır

Yanıt (Response)

Başarılı bir istek, gönderim sürecini takip etmek için kullanılacak bulkMessageId'yi döner:

{
"bulkMessageId": "abc123xyz789"
}

Hata Yanıtları

DurumAçıklama
Channel not foundchannelUsername ve connectorBrand ile eşleşen doğrulanmış kanal bulunamadı
Channel is not verifiedBulunan kanal henüz doğrulanmamış
invalidRequestAlıcı için birden fazla tanımlayıcı verildi, aynı alıcı listede tekrar ediyor veya payload eksik
channelNotFoundVerilen channelId ile eşleşen aktif kanal bulunamadı
schema-errorİstek gövdesindeki bir alan şema doğrulamasından geçemedi (zorunlu alan eksik, yanlış tip veya izin verilmeyen değer)

Dönen bulkMessageId, gönderim istatistiklerini sorgulamak ve gönderimi durdurmak için aşağıdaki endpointlerde kullanılabilir.


Stats — Gönderim İstatistikleri

Bir bulk mesajın anlık gönderim durumunu sorgular. Bekleyen, başarılı, başarısız ve iptal edilen kayıt sayılarını döner.

POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/stats.js

İstek Parametreleri

ParametreTipZorunluAçıklama
bulkMessageIdstringEvetTakip edilecek bulk mesajın ID'si (createBulkPerRecipient'ten dönen değer)
{
"bulkMessageId": "abc123xyz789"
}
curl --location 'https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/stats.js' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_TOKEN' \
--data '{
"bulkMessageId": "abc123xyz789"
}'

Response

{
"bulkMessage": {
"_id": "abc123xyz789",
"slug": "my-workspace",
"title": "Kampanya Başlığı",
"channelUsername": "908506669933",
"connectorBrand": "whatsapp",
"connectorSlug": "whatsapp-cloud",
"payload": {
"recipientCount": 100,
"defaultPayloadType": "template",
"jobId": "job_abc123"
},
"schedule": {
"date": "2026-06-10T07:00:00.000Z",
"type": "later"
},
"createdAt": "2026-06-08T10:00:00.000Z",
"updatedAt": "2026-06-08T10:30:00.000Z"
},
"stats": {
"pending": 45,
"success": 42,
"failed": 3,
"cancelled": 10,
"total": 100
}
}

Stats Alanları

AlanTipAçıklama
stats.pendingnumberHenüz işlenmemiş, kuyruktaki kayıt sayısı
stats.successnumberGönderim işlemi başarıyla tamamlanmış kayıt sayısı
stats.failednumberGönderim hatası alan kayıt sayısı
stats.cancellednumberİptal edilmiş kayıt sayısı
stats.totalnumberToplam kayıt sayısı (pending + success + failed + cancelled)
not

stats.success, mesajın sisteme başarıyla iletildiğini gösterir; Meta'nın mesajı alıcıya ulaştırdığını garanti etmez. Meta'nın sonraki aşamalarda ürettiği durum bildirimleri (delivered, read, failed vb.) bu sayacı etkilemez ve burada yansıtılmaz.


Stop — Gönderimi Durdur

Devam eden bir bulk mesaj gönderimini durdurur. Kuyruktaki job iptal edilir ve tüm pending kayıtlar cancelled statüsüne çekilir. Halihazırda gönderilmiş (success) veya hata almış (failed) kayıtlar etkilenmez.

POST https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/stop.js
uyarı

Bu işlem geri alınamaz. Durdurulan gönderimi yeniden başlatmak mümkün değildir.

İstek Parametreleri

ParametreTipZorunluAçıklama
bulkMessageIdstringEvetDurdurulacak bulk mesajın ID'si
{
"bulkMessageId": "abc123xyz789"
}
curl --location 'https://app.monochat.ai/api/:slug/custom-functions/bulk-message-api-app/api/bulk-message/stop.js' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_TOKEN' \
--data '{
"bulkMessageId": "abc123xyz789"
}'

Response

Başarılı durumda yanıt gövdesi boştur. HTTP 200 durumu işlemin başarıyla tamamlandığını gösterir.

{}
ipucu
  • Yalnızca bu API üzerinden oluşturulan bulk mesajlar durdurulabilir
  • Gönderimi durdurduktan sonra stats endpointi ile iptal edilen kayıt sayısını doğrulayabilirsiniz
  • Bulk mesaj bulunamazsa hata döner: bulkMessageNotFound