WhatsApp şablonuyla mesaj gönderme
Kendi sisteminizden bir telefon numarasına onaylı bir WhatsApp şablonu gönderirsiniz. Şablonun başında resim, belge ya da video varsa dosyanın bağlantısını da verirsiniz. Örnek: sisteminizde tamamlanan her işlem için müşteriye bir belge görseli ve işlemin bilgileri.
/v1/whatsapp/conversations
WhatsApp, işletmenin kendisine son 24 saatte yazmamış birine serbest metin göndermesine izin vermez. Böyle bir numaraya ilk mesaj, Meta'nın onayladığı bir şablonla gider. Numarayla daha önce yazışmış olmanız gerekmez.
Akış
- Şablon listesini bir kez okuyunKullanacağınız şablonun
refdeğerini ve gönderebileceği hatları (line_keys) alın. - Her işlemde gönderim ucunu çağırınNumara, şablon, değişken değerleri ve varsa dosya bağlantısı. İşlem numaranızı tekrar anahtarı olarak verin.
- Gerekirse teslim durumunu sorgulayınMesajın iletildiğini ve okunduğunu mesaj listesinden okursunuz.
Temel adres ve anahtarın isteğe nasıl konacağı: Temel adres ve kimlik doğrulama. Anahtarda WhatsApp uygulaması işaretli olmalı.
1. Şablon listesi
/v1/whatsapp/templates
Firmanızın bağlı WhatsApp Business hesaplarındaki onaylı şablonları verir. Liste her istekte Meta'dan okunur; yeni onaylanan şablon kendiliğinden görünür. Bu uç ücretsizdir, müşteriye mesaj çıkmaz.
Sorgu parametresi
| Ad | Tür | Açıklama |
|---|---|---|
| used_by | string | Boş, AGENT, SYSTEM ya da ALL. Panelde şablona verilen kullanım işaretine göre süzer. Boşsa personelin kullandığı ve işaretsiz şablonlar gelir; sistem gönderimine ayrılmış şablonlar (SYSTEM) gelmez. Hepsini görmek için ALL kullanın. Süzgeç yalnız listeyi daraltır: refini bildiğiniz şablon listede görünmese de gönderilebilir. |
Örnek yanıt · 200
{
"templates": [
{
"ref": "12:islem_bildirimi",
"name": "islem_bildirimi",
"language": "tr",
"category": "UTILITY",
"status": "APPROVED",
"used_by": "SYSTEM",
"body": "Sayın {{1}}, {{2}} numaralı işleminiz tamamlandı. Tarih: {{3}}.",
"placeholders": 3,
"header_format": "IMAGE",
"line_keys": ["<HAT_ANAHTARI>"],
"fields": [
{ "slot": "1", "value": "" },
{ "slot": "2", "value": "" },
{ "slot": "3", "value": "" }
],
"needs_place": false
}
],
"place": ""
}Kullanacağınız alanlar
| Alan | Açıklama |
|---|---|
| ref | Gönderimde template alanına yazılacak değer. Şablonun adıyla birlikte bağlı olduğu hesabı da taşır; aynı ad iki hesapta bulunabildiği için yalnız ad yetmez. |
| body | Müşterinin okuyacağı metin, yer tutucularıyla. |
| placeholders | Metindeki yer tutucu sayısı; variables dizisi bu kadar değer taşır. |
| header_format | Başlığın türü: IMAGE, DOCUMENT ya da VIDEO. Bu durumda gönderimde media verilir. Başlıksız şablonda alan gelmez. |
| line_keys | Bu şablonun gönderilebileceği hatlar. Gönderimde line alanına bunlardan biri yazılır. |
| category | Meta'nın verdiği kategori; gönderimin ücret kalemini belirler. |
| fields | Her yer tutucunun kutusu. Firmanızın panelde bağladığı değer (şube adı gibi) varsa mapped_slots listesinde yer alır; o sıraları boş bırakabilirsiniz. |
2. Gönderim
/v1/whatsapp/conversations
Numarayla konuşmayı açar (varsa var olanı kullanır) ve şablonu gönderir. Bu uç ücretlidir; bkz. Ücret. Örnek istek sağ sütunda.
Başlıklar
| Ad | Tür | Açıklama |
|---|---|---|
| Authorizationzorunlu | string | Bearer <API_ANAHTARINIZ> |
| Content-Typezorunlu | string | application/json |
| Idempotency-Key | string | Tekrar anahtarı; bkz. Tekrar anahtarı. |
Gövde alanları
Tabloda olmayan bir alan gönderilirse istek 400 BAD_REQUEST ile reddedilir.
| Alan | Tür | Açıklama |
|---|---|---|
| tozorunlu | string | Alıcının numarası, ülke koduyla: 905XXXXXXXXX. Rakam dışındaki karakterler (+, boşluk, tire) yok sayılır. |
| templatezorunlu | string | Şablon listesindeki ref değeri. |
| linekoşullu | string | Mesajın çıkacağı hat; şablonun line_keys değerlerinden biri. Seçilebilecek birden çok hat varsa zorunludur. Her istekte vermenizi öneririz. |
| language | string | Şablonun dil kodu, örneğin tr. Boşsa şablonun kendi dili kullanılır. |
| variableskoşullu | string[] | Yer tutucuların değerleri, sırayla: ilk eleman {{1}}, ikincisi {{2}}. Şablonda yer tutucu varsa her biri dolu olmalı. Boş dize bırakılan sırayı firmanızın panelde bağladığı değer doldurur; bağlı değer yoksa istek reddedilir. |
| mediakoşullu | object | Başlığı dosya olan şablonda zorunlu. Alanları aşağıda. |
| expected | string | Müşteriye gidecek metnin sizin ekranınızda gösterdiğiniz hâli. Verilirse gidecek metin bununla aynı olmalı; değilse mesaj gönderilmez ve 409 TEMPLATE_CHANGED döner. |
| place | string | Şablon şube bilgisi içeriyorsa şubenin kodu (GET /v1/whatsapp/places). Firmanın tek şubesi varsa gerekmez. |
| agent | object | Konuşmayı sizin sisteminizdeki bir personele bağlar: {"external_id": "...", "name": "..."}. Programla yapılan gönderimlerde verilmez. |
media alanları
| Alan | Tür | Açıklama |
|---|---|---|
| kindzorunlu | string | IMAGE, DOCUMENT ya da VIDEO. Şablonun başlık türüyle aynı olmalı. |
| linkzorunlu | string | Dosyanın bağlantısı. Dosya VeriTakibi'ye yüklenmez; bağlantı olduğu gibi Meta'ya iletilir ve dosyayı Meta bu adresten indirir. Bu yüzden bağlantı herkese açık bir HTTPS adresi olmalı, oturum açma istememeli. |
| filename | string | Yalnız DOCUMENT için: müşterinin telefonunda görünecek dosya adı, örneğin belge.pdf. |
Değer kuralları
- Bir değer satır sonu ya da sekme içeremez.
- Bir değerde dörtten fazla ardışık boşluk olamaz.
- Değerler yerleştikten sonra metin 1024 karakteri geçemez.
Kurala uymayan istek gönderilmez; 400 TEMPLATE_VALUE_INVALID hangi sıranın neden reddedildiğini söyler.
Başarılı gönderim 200 döner ve açılan konuşmayı verir (sağ sütunda yanıtın bir kısmı). id konuşmanın kimliğidir; kendi kaydınızda işlemle birlikte saklayın, teslim durumunu bununla sorgularsınız.
Teslim ve okunma durumu
/v1/whatsapp/conversations/{id}/messages
Mesajın telefona ulaşıp ulaşmadığını ve okunup okunmadığını sorgulayarak öğrenirsiniz. VeriTakibi bu durum değişikliklerini sizin sisteminize bildirmez; bildirim (itme) yok, gerektiğinde bu ucu çağırırsınız. {id} gönderim yanıtındaki konuşma kimliğidir. Bu uç ücretsizdir.
Yanıt konuşmanın mesajlarını verir. Giden mesajlarda ("direction": "OUT") şu alanlar bulunur:
| Alan | Tür | Açıklama |
|---|---|---|
| delivered_at | string | Mesajın alıcının telefonuna ulaştığı an; RFC 3339, UTC. Henüz bilinmiyorsa alan gelmez. |
| read_at | string | Alıcının mesajı okuduğu an; RFC 3339, UTC. Henüz bilinmiyorsa alan gelmez. |
| delivery_state | string | SENT: mesaj gönderildi. FAILED: gönderim başarısız oldu. |
| delivery_error_code | string | Gönderim başarısız olduysa sağlayıcının hata kodu. |
Örnek yanıt · 200 (kısaltılmış)
{
"messages": [
{
"id": 90211,
"direction": "OUT",
"sent_at": "2026-10-12T06:30:05Z",
"delivered_at": "2026-10-12T06:30:07Z",
"read_at": "2026-10-12T06:41:52Z",
"delivery_state": "SENT",
...
}
],
"next_id": 0
}Tekrar anahtarı
Ağ koptuğunda ya da yanıt gelmediğinde isteği yeniden göndermeniz gerekir. Tekrar anahtarı olmadan her yeniden deneme yeni bir mesaj ve yeni bir ücret demektir. İsteğe bağlı Idempotency-Key başlığı bunu önler.
- Kendi sisteminizdeki işlem numarasını anahtar yapın, örneğin
islem-A000123. Aynı işlem için her denemede aynı anahtarı, farklı işlemler için farklı anahtarlar kullanın. - Anahtar en çok 255 karakterdir ve satır sonu gibi denetim karakteri içeremez; uymayan başlık
400 BAD_REQUESTalır. - Anahtarlar firmanıza özeldir; başka bir firmanın anahtarıyla çakışmaz.
| Durum | Yanıt |
|---|---|
| Aynı anahtar, aynı gövde, ilk istek başarılı | 200, ilk isteğin konuşması ve Idempotent-Replayed: true başlığı. İkinci mesaj gönderilmez, ikinci ücret yazılmaz. |
| Aynı anahtar, farklı gövde | 409 IDEMPOTENCY_KEY_REUSED. Hiçbir şey gönderilmez. |
| İlk istek sürüyor ya da sunucu yoğun | 409 IDEMPOTENCY_IN_PROGRESS ve Retry-After: 1. Retry-After kadar (saniye) bekleyip aynı anahtarla yeniden deneyin. |
| İlk istek hata almıştı | Yalnız başarılı gönderim hatırlanır. Sorunu giderip aynı anahtarla yeniden denediğinizde gönderim yapılır. |
Gövdeler karşılaştırılırken numaranın yazılışı (+90… ile 90…) ve alanların sırası fark yaratmaz.
Yeniden deneme kuralı
| Aldığınız sonuç | Ne yapmalı |
|---|---|
| Yanıt yok, zaman aşımı, 500, 502 | Aynı anahtarla yeniden deneyin. İlk istek gitmişse ikinci deneme yalnız ilk sonucu döner. |
| 409 IDEMPOTENCY_IN_PROGRESS | Retry-After kadar bekleyip aynı anahtarla yeniden deneyin. |
| 429 RATE_LIMITED | Bir süre bekleyip aynı anahtarla yeniden deneyin. |
| 402 OVER_CREDIT_LIMIT | Bakiye düzeldikten sonra aynı anahtarla yeniden deneyin. |
| Öteki 4xx yanıtlar | Yeniden denemeyin; önce isteği ya da ayarı düzeltin. |
Hatalar
Hata gövdesi bir kod taşır. Bazı kodlarda detail alanı da gelir:
{ "error": "TEMPLATE_VALUE_INVALID", "detail": { "slot": "2", "reason": "unresolved" } }| Kod | HTTP | Anlamı | Ne yapmalı |
|---|---|---|---|
| BAD_REQUEST | 400 | Gövde okunamadı, bilinmeyen alan var, to ya da template boş, line tanınmıyor ya da Idempotency-Key geçersiz. Şablon listesinde used_by tanınmıyor. | İsteği düzeltin. |
| LINE_REQUIRED | 400 | Hangi hattan gönderileceği belli değil: birden çok hat var ve line verilmedi, ya da şablonun hesabında gönderilebilecek hat bulunamadı. | line alanına şablonun line_keys değerlerinden birini yazın. |
| TEMPLATE_VALUE_INVALID | 400 | Bir değer kurala uymuyor. detail.slot sırayı, detail.reason sebebi verir: unresolved (boş ya da eksik), line_break (satır sonu ya da sekme), spaces (fazla boşluk), long (değer çok uzun), body_long (metnin tamamı 1024 karakteri geçiyor). | Değeri düzeltin. Mesaj gönderilmedi. |
| UNAUTHORIZED | 401 | Anahtar yok, yanlış ya da iptal edilmiş. | Anahtarı kontrol edin. |
| OVER_CREDIT_LIMIT | 402 | Bakiye kredi limitini aştı; giden mesajlar kapalı. Gönderim denenmedi. | Bakiye düzeldikten sonra yeniden deneyin. |
| FORBIDDEN | 403 | Anahtarda WhatsApp işaretli değil ya da istek izinli adreslerin dışından geldi. | Panelde anahtarın ayarını kontrol edin. |
| PLACE_NOT_FOUND | 404 | place kodu tanınmıyor. | Şube listesinden geçerli bir kod verin. |
| IDEMPOTENCY_KEY_REUSED | 409 | Aynı tekrar anahtarı farklı bir gövdeyle kullanıldı. | Her işleme ayrı anahtar verin. |
| IDEMPOTENCY_IN_PROGRESS | 409 | Aynı anahtarlı ilk istek sürüyor ya da sunucu o an yoğun. | Retry-After kadar bekleyip aynı anahtarla yeniden deneyin. |
| TEMPLATE_CHANGED | 409 | expected verildi ve gidecek metin ondan farklı. detail.body gidecek metni verir. Mesaj gönderilmedi. | Şablonu yeniden okuyun ve metni güncelleyin. |
| CONVERSATION_BLOCKED | 409 | Numara firmanızca engellenmiş. Mesaj gönderilmedi. | Engeli panelden kaldırmadan göndermeyin. |
| ALREADY_CLAIMED | 409 | Yalnız agent verildiğinde: konuşma başka bir personelde. Mesaj gönderilmedi. | Programla yapılan gönderimde agent vermeyin. |
| RATE_LIMITED | 429 | Anahtar başına dakikada 300 istek sınırı aşıldı. | Bekleyip yeniden deneyin. |
| INTERNAL | 500 | Sunucu isteği tamamlayamadı. | Aynı anahtarla yeniden deneyin. |
| SEND_FAILED | 502 | Gönderim yapılamadı ya da sağlayıcı reddetti; örneğin başlığı dosya olmayan şablona media verildi ya da media.kind geçersiz. | İsteği kontrol edin; geçici bir arızaysa aynı anahtarla yeniden deneyin. |
| TEMPLATES_UNAVAILABLE | 502 | Şablonlar Meta'dan okunamadı (şablon listesinde ya da expected verilen gönderimde). | Bir süre sonra yeniden deneyin. |
Ücret
- Her başarılı gönderim ücretlidir.
- Ücret kalemi şablonun kategorisine göre belirlenir: pazarlama, bilgilendirme ya da doğrulama. Kategoriyi Meta verir ve gönderimden sonra bildirir.
- Bakiye kredi limitini aşmışsa gönderim hiç denenmez ve
402 OVER_CREDIT_LIMITdöner. - Tekrar anahtarıyla yakalanan yeniden deneme ikinci bir ücret yazmaz.
TEMPLATE_VALUE_INVALIDveTEMPLATE_CHANGEDistek Meta'ya çıkmadan verilir; ücret yazılmaz.- Şablon listesini ve mesaj listesini okumak ücretsizdir.