Webhook'lar
UPPU her olayı HTTPS uç noktanıza imzalı bir POST isteğiyle, her istekte tek olay olarak gönderir. Bu sayfa uç noktanın nasıl kurulacağını, imzanın nasıl doğrulanacağını, yanıtı ve yeniden denemeleri, kesintiden sonra eksiğin nasıl tamamlanacağını ve her olayın neye benzediğini anlatır.
Uç noktayı kurun
Uç noktaları firma sahibi UPPU panelinde yönetir: firmanın ayarları, ardından Webhook'lar (parola onayından sonra); bir API anahtarıyla API'den de yönetilir. Bir firmanın en çok 5 uç noktası olur.
- Adres: 443 numaralı porttan
https, genel bir alan adı ve geçerli bir sertifika. Yönlendirmeler izlenmez. - Olaylar: alınacak olay türleri; yeni uç nokta olay tablosundaki varsayılanlarla başlar. Kanal süzgeci (tek kanal ya da hepsi), sıralama (
best_effortya dastrict) ve aynı anda yolda olabilecek en çok teslimat (1-32, varsayılan 8). - İmza sırrı:
whsec_..., uç nokta oluşturulurken bir kez gösterilir. Parola gibi saklayın.
Etkinleştirme. Yeni uç nokta ancak iki denetimden sonra olay alır; ikisi de son 60 dakika içinde geçmiş olmalıdır:
- Alıcınızı imza doğrulamasıyla birlikte yayına alın.
- Test olayı gönder: UPPU sırrınızla imzalanmış örnek bir olay gönderir; uç noktanız
2xxdönmelidir. - Yanlış imzalı deneme gönder: UPPU yanlış bir sırla imzalanmış
webhook.testgönderir; uç noktanız onu2xxdışında herhangi bir durumla reddetmelidir. Bu, imzayı denetlediğinizi gösterir. - Etkinleştir.
Uç nokta etkin değilken oluşan olaylar ona teslim edilmez; onları GET /v1/events ile alın.
UPPU'nun çıkış adresi panelin Webhook'lar sayfasında yazar ve değişmeden 30 gün önce duyurulur. Yalnızca IP süzgecine güvenmeyin: olayın UPPU'dan geldiğini kanıtlayan imzadır.
Uç noktaları API'den yönetin
webhooks:manage kapsamlı bir API anahtarı paneldeki uç noktaların aynısını /v1/webhook-endpoints'te yönetir: listeler, oluşturur, değiştirir ve siler, test olayı ya da yanlış imzalı deneme gönderir, etkinleştirir ve kapatır, imza sırrını döndürür. Bu kapsam hiçbir hazır seçimde yoktur ve var olan anahtarlarda yoktur: firma sahibi Geliştiriciler sayfasında Özel seçimle bir anahtara ekler. Kurallar, 5 uç nokta sınırı ve denetim kayıtları panelinkilerdir; bir uç nokta daha 409 plan_limit_reached alır.
- Sır bir kez gösterilir:
POST /v1/webhook-endpoints'in vePOST /v1/webhook-endpoints/{id}/secret'in yanıtında, başka hiçbir yerde. AynıIdempotency-Key'li tekrar sırsız yanıtlanır: ilk yanıtı kaybettiyseniz sırrı döndürün. - Etkinleştirme paneldeki gibidir:
POST /v1/webhook-endpoints/{id}/test,POST /v1/webhook-endpoints/{id}/probe, sonraPOST /v1/webhook-endpoints/{id}/activate. Test ve deneme alıcınızı bekler (en çok 10 saniye): firma başına dakikada en çok 10 ve aynı anda bir. Beklemesi gereken denetimconcurrent_checksnedeniyle429 rate_limitedalır ve gönderilmez:Retry-After'dan sonra yeniden gönderin. - Yeni adres hemen denetlenir:
POST /v1/webhook-endpointsveurl'liPATCHalan adını istek sırasında DNS'te sorar; bu denetim test ve denemelerle birlikte firma başına aynı anda birdir. Beklemesi gereken yazımconcurrent_checksnedeniyle429 rate_limitedalır ve hiçbir şeyi değiştirmez:Retry-After'dan sonra yeniden gönderin. Bu yazımlar dakikadaki 10'a sayılmaz. - Tek kanala bağlı anahtar yalnızca kendi kanalına süzülmüş uç noktaları görür ve yönetir.
Haftalık test olayı
Bir uç nokta haftalık test olayını açabilir: panelin uç nokta formundan ya da API'de weekly_test: true ile (varsayılan kapalı). UPPU o zaman haftada bir, uç nokta etkin ya da başarısızken, uç noktanın sırrıyla imzalanmış test: true'lu bir webhook.test gönderir. Geçmeyen haftalık test yalnızca uyarıdır: panel uç noktada, API weekly_test.failed_at'te gösterir. Uç nokta bu yüzden hiç askıya alınmaz ve teslimatlar sürer. Uyarıyı geçen haftalık test ya da test olayı, haftalık testin kapatılması ve yeni adres kaldırır.
İstek
| Başlık | Değer |
|---|---|
Content-Type |
application/json; charset=utf-8 |
User-Agent |
UPPU-Webhooks/1.0 |
webhook-id |
Olayın kimliği; yeniden denemelerde, yeniden gönderimlerde ve uç noktalarda aynı; gövdenin id'sine eşit |
webhook-timestamp |
Unix saniyesi, her denemede yeni |
webhook-signature |
v1,<base64>; sır yenilenirken boşlukla ayrılmış iki değer |
Uppu-Event-Type |
Olay türü, örneğin message.status |
Uppu-Delivery-Id |
Bu uç noktaya bu teslimat; yeniden gönderim onu korur |
Uppu-Attempt |
İlk denemede 1 |
Gövde sıkıştırılmış UTF-8 JSON'dur ve her denemede aynı baytlardır:
{
"id": "01jace0e1v2m4n6p8q0r2s4t6a",
"object": "event",
"type": "message.received",
"api_version": "v1",
"created_at": "2026-10-20T09:15:01.020Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": {"id": "01j9z0ch5k2m4n6p8q0r2s4t6v", "type": "whatsapp"},
"test": false,
"data": {}
}
- Kanalı olmayan olayda (
template.updated)channelnull'dır. testyalnızca panelin test olaylarındatrue'dur:2xxdönün ve başka bir şey yapmayın.- Bir olay en çok 256 KB'tır. Daha büyüğü kısaltılır: iç içe nesneler yalnızca
id'lerini tutar, uzun metinler kesilir vedata.truncatedtrueolur. Mesajın tamamınıGET /v1/messages/{id}ile okuyun.
İmzayı doğrulayın
UPPU her isteği Standard Webhooks yöntemiyle imzalar:
- Anahtar: sırdan
whsec_'i atın, kalanı base64 ile çözün. Anahtar çözülen baytlardır, sırrın metni değil. - İmzalanan içerik:
webhook-id+.+webhook-timestamp+.+ ham gövde, tam alındığı gibi. Denetimden önce JSON'u asla çözüp yeniden kodlamayın. - İmza: imzalanan içeriğin anahtarla HMAC-SHA256'sı, dolgulu standart base64.
- Karşılaştırın:
webhook-signature'ı boşluklardan bölün; değeri sizin imzanıza sabit zamanlı karşılaştırmayla eşit olan birv1,<değer>parçası isteği geçerli kılar. - Reddedin:
webhook-id'si olmayan, zaman damgası yalnızca rakam olmayan ya da zaman damgası saatinizden 300 saniyeden fazla uzak olan isteği (saatinizi NTP ile eşit tutun).
Sır yenilenirken UPPU 24 saat boyunca hem yeni hem eski sırla imzalar; iki sır da isteği doğrular. Alıcınızı bu 24 saat içinde yeni sırra geçirin.
Hazır kod: PHP, Node.js, Python ve C#.
Deneme vektörü. Standard Webhooks belirtiminin yayımlanmış deneme vektörü bir uygulamayı çevrimdışı sınar:
| Değer | |
|---|---|
| Sır | whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw |
webhook-id |
msg_p5jXN8AQM9LWM0D4loKWxJek |
webhook-timestamp |
1614265330 |
| Gövde | {"test": 2432232314} |
webhook-signature |
v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE= |
Saatinizi vektörün zaman damgasına ayarlayarak sınayın; sır herkese açık bir örnektir, asla gerçek bir sır değildir.
Hızlı yanıt verin
- 10 saniye içinde
2xxdönün (bağlantı 5 saniyede kurulmalı). Olayı saklayın,204dönün, sonra işleyin. - Tekrarları ayıklayın: teslim en az bir kezdir; her
webhook-id'yi en az 35 gün hatırlayın ve gördüğünüz kimliğe2xxdönün. - Hata yanıtına kişisel veri koymayın: UPPU başarısız yanıtın ilk 191 karakterini panel için saklar.
Yeniden deneme, sıra ve askıya alma
- Başarı her
2xx'tir. Diğer her yanıt,3xxve4xxdahil, zaman aşımı ve kurulamayan bağlantı yeniden denenir. - Deneme takvimi: 0, 30 saniye, 2 dakika, 10 dakika, 30 dakika, 1 saat, 2 saat, 4 saat, 8 saat, 12 saat, 24 saat ve 24 saat (±%10): yaklaşık 76 saatte 12 deneme, sonra teslimat ölü sayılır.
Retry-After'lı429ya da503(saniye ya da HTTP tarihi, en çok bir saat) en az o kadar bekletir, ama yine başarısız deneme sayılır.410uç noktayı hemen askıya alır. Bunu istemiyorsanız410dönmeyin.- Başarısız ve askıda: art arda 20 başarısızlıktan sonra uç nokta başarısız sayılır ve bir yanıt
2xxolana kadar dakikada bir deneme alır. 72 saat başarısız kalırsa askıya alınır: hiçbir şey gönderilmez, yeni olaylar en çok 7 gün bekletilir. Firma sahibi ve yöneticiler e-posta alır. Uç noktayı panelden yeniden açın: bir test olayı geçmeli, sonra bekleyen olaylar sırayla gelir. - Yeniden gönderim: panel 30 gün boyunca tek bir teslimatı ya da belli bir andan beri ölen bütün teslimatları yeniden gönderir;
webhook-idve baytlar aynı kalır. - Sıra: olaylar kişi başına (o olaylarda şablon ya da kanal başına) kuyruğa girer ve her kuyrukta aynı anda en çok bir teslimat yoldadır.
best_effort'ta (varsayılan) yeniden denemeyi bekleyen teslimat sonraki olayları bekletmez; olayları sırasız görebilirsiniz.strict'te en eski teslim edilmemiş olay, teslim edilene ya da ölene kadar kuyruğunu tıkar; sohbet botu gibi bir durum makinesi için onu seçin. - Durumlar yalnızca ileri gider:
message.statusprevious_statustaşır. Durumlarıqueued<accepted=unknown=expired<sent<failed<delivered<readdiye sıralayın ve sırası saklı olandan büyük olmayan olayı yok sayın:failed'dan sonra yinedeliveredgelebilir,expired'dan sonra da ağın sonraki her durumu (sent,failed,delivered,read) gelebilir.
Kaçırılan olaylar
GET /v1/events (kapsam events:read, anahtar başına saniyede 2 istek) son 7 günün olaylarını webhook'larla aynı kimlik ve gövdelerle, eskiden yeniye döner.
after=<olay kimliği>: işlediğiniz son olay;types=message.received,message.statussüzer;limit1-100.next_cursor'ı (afterolarak verin)nullolana kadar izleyin.- Son 10 saniyenin olayları sonraki çağrıda görünür.
- Tek kanala bağlı anahtar yalnızca o kanalın olaylarını görür,
template.updated'i hiç görmez. - Bilinmeyen, 7 günden eski ya da anahtarın göremediği bir
after422 validation_failed(alanafter) alır:after'sız yeniden başlayın, tekrarları ayıklamanız düşürsün.
Olaylar
| Olay | Varsayılan abonelik | Sıralama |
|---|---|---|
message.received | evet | kişi |
message.status | evet | kişi |
message.created | hayır | kişi |
contact.identity_changed | evet | kişi |
contact.consent_changed | hayır | kişi |
contact.erased | evet | kişi |
template.updated | hayır | şablon |
channel.status_changed | evet | kanal |
channel.health_changed | hayır | kanal |
conversation.updated | hayır | kişi |
contact.reachability_changed | evet | kişi |
contact.updated (henüz üretilmiyor) | hayır | kişi |
account.service_stop_scheduled | evet | firma hesabı |
account.service_resumed | evet | firma hesabı |
webhook.test | her zaman gönderilir | sırasız |
v1 içinde bilinmeyen olay türleri ve alanlar gelebilir: onları yok sayın. Aşağıdaki örnekler olayların tamamını gösterir; kimlikler ve değerler örnektir.
message.received
Bir kişi herhangi bir kanaldan mesaj gönderdi. data.message mesajdır, data.contact kişidir (identities bu kanaldaki tür başına güncel kimliği taşır; örneğin phone, bsuid, psid, igsid, telegram ya da web_visitor), data.conversation konuşma, data.service_window yanıt penceresidir (web sohbetinde ve Telegram'da null).
- Kişiyi
data.contact.idile tutun; okundu bildirimi ve yanıt içindata.message.id'yi kullanın. - Kendiliğinden serbest yanıt vermeden önce
service_window.open'a vecloses_at'e bakın. - Medya
statependingile gelir;GET /v1/media/{id}/contentile indirin (UPPU indirirkenRetry-After'lı409 media_not_ready). Dosya hazır olunca ayrıca olay gelmez. - Engelli kişiler, sistem bildirimleri, tekrarlar ve bilinmeyen mesajlara tepkiler için gönderilmez.
- Tamamlanan WhatsApp formu (WhatsApp Flows)
content.typeflow_replyolarak gelir:flow_token(akış mesajınızın jetonu),flow_id(kişi UPPU'dan gönderilen bir akış mesajını yanıtladıysa, yoksanull) veresponse, akışınızın tanımladığı biçimde formun verisi. Saklanamayacak kadar büyük yanıttaresponsenull,response_omittedtoo_largeya datoo_deepolur. Dosya alanı yalnızcafile_name,mime_typevesha256taşır. WhatsApp kanalıcapabilities.interactive_types'taflowlistelemediği sürece tamamlanan formunsupported(provider_typenfm_reply) olarak gelir.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6a",
"object": "event",
"type": "message.received",
"api_version": "v1",
"created_at": "2026-10-20T09:15:01.020Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": {
"id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"type": "whatsapp"
},
"test": false,
"data": {
"message": {
"object": "message",
"id": "01jab3t6ms2m4n6p8q0r2s4t6v",
"channel_id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"channel_type": "whatsapp",
"conversation_id": "01jab39zcv2m4n6p8q0r2s4t6v",
"contact_id": "01j8x7ct5k2m4n6p8q0r2s4t6v",
"direction": "in",
"author": {
"type": "contact",
"label": "Deniz",
"api_key_prefix": null
},
"content": {
"type": "text",
"text": {
"body": "Hello, where is my order?"
}
},
"context": null,
"template": null,
"preview": "Hello, where is my order?",
"status": "received",
"status_changed_at": null,
"error": null,
"client_reference": null,
"provider_message_id": "PROVIDER-MESSAGE-ID",
"sent_at": "2026-10-20T09:15:00.000Z",
"received_at": "2026-10-20T09:15:01.000Z",
"created_at": "2026-10-20T09:15:01.000Z"
},
"contact": {
"id": "01j8x7ct5k2m4n6p8q0r2s4t6v",
"display_name": "Deniz",
"identities": {
"phone": "+447700900100",
"bsuid": "TR.ExampleUser1"
}
},
"conversation": {
"id": "01jab39zcv2m4n6p8q0r2s4t6v",
"status": "open",
"handling": "api"
},
"service_window": {
"open": true,
"closes_at": "2026-10-21T09:13:00.000Z"
}
}
}
message.status
Giden bir mesajın durumu ilerledi: accepted, unknown, sent, delivered, read, failed ya da expired (queued hiç gelmez). Her yazar için gönderilir: API anahtarınız, ekip, UPPU Bot, panelin kampanyası. Gönderiminizle data.message.id ya da data.message.client_reference üzerinden eşleyin; failed'da data.error.code nedeni söyler. expired (kod ttl_expired), UPPU'nun zamanında sağlayıcıya veremediği ttl'li bir gönderimden sonra gelir: hiçbir şey gönderilmedi, previous_status queued. Önceki bir deneme sağlayıcıdan hata yanıtı aldıysa ttl gönderimi bunun yerine o hatayla failed bitirir. Sağlayıcı mesajı yine de aldıysa (UPPU ona ulaşamadı ve denemeyi gitmemiş saydı; seyrek), o denemenin sonraki durumu expired'dan sonra gelir. Kampanya durdurulduğunda ya da iptal edildiğinde sağlayıcıya henüz ulaşmamış kampanya mesajı (yazar türü campaign) da expired (kod ttl_expired) ya da önceki denemenin hatasıyla failed biter.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6b",
"object": "event",
"type": "message.status",
"api_version": "v1",
"created_at": "2026-10-20T09:20:03.010Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": {
"id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"type": "whatsapp"
},
"test": false,
"data": {
"message": {
"id": "01jab3a1k9f2m4n6p8q0r2s4t6",
"channel_id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"conversation_id": "01jab39zcv2m4n6p8q0r2s4t6v",
"contact_id": "01j8x7ct5k2m4n6p8q0r2s4t6v",
"provider_message_id": "PROVIDER-MESSAGE-ID",
"client_reference": "order-1001",
"author": {
"type": "api",
"api_key_prefix": "Ab12Cd34Ef56"
}
},
"status": "delivered",
"previous_status": "sent",
"occurred_at": "2026-10-20T09:20:03.004Z",
"error": null
}
}
message.created
Giden bir mesaj kuyruğa alındı: gelen kutusunda bir temsilci, UPPU, UPPU Bot, panelin bir kampanyası (yazar türü campaign, toplu şablon mesajları) ya da bir API anahtarı tarafından. data message.received biçimindedir; direction out, status queued. Ekibin yanıtlarını kendi sisteminizde göstermek için kullanın.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6c",
"object": "event",
"type": "message.created",
"api_version": "v1",
"created_at": "2026-10-20T09:20:00.130Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": {
"id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"type": "whatsapp"
},
"test": false,
"data": {
"message": {
"object": "message",
"id": "01jab3a1k9f2m4n6p8q0r2s4t6",
"channel_id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"channel_type": "whatsapp",
"conversation_id": "01jab39zcv2m4n6p8q0r2s4t6v",
"contact_id": "01j8x7ct5k2m4n6p8q0r2s4t6v",
"direction": "out",
"author": {
"type": "api",
"label": "Order bot",
"api_key_prefix": "Ab12Cd34Ef56"
},
"content": {
"type": "text",
"text": {
"body": "Your order has shipped.",
"preview_url": false
}
},
"context": null,
"template": null,
"preview": "Your order has shipped.",
"status": "queued",
"status_changed_at": "2026-10-20T09:20:00.120Z",
"error": null,
"client_reference": "order-1001",
"provider_message_id": null,
"sent_at": null,
"received_at": null,
"created_at": "2026-10-20T09:20:00.120Z"
},
"contact": {
"id": "01j8x7ct5k2m4n6p8q0r2s4t6v",
"display_name": "Deniz",
"identities": {
"phone": "+447700900100",
"bsuid": "TR.ExampleUser1"
}
},
"conversation": {
"id": "01jab39zcv2m4n6p8q0r2s4t6v",
"status": "open",
"handling": "api"
},
"service_window": {
"open": true,
"closes_at": "2026-10-21T09:13:00.000Z"
}
}
}
contact.identity_changed
Bir kişinin WhatsApp kullanıcı kimliği değişti. data.contact_id aynı kalır; saklı kimliği previous'tan current'a güncelleyin. reason değişikliği neyin bildirdiğini söyler: çoğunlukla user_changed_user_id (WhatsApp'ın konuşmadaki bildirimi), kişi telefon numarasını değiştirdiyse user_changed_number (WhatsApp o zaman ona yeni bir kullanıcı kimliği de verir), sahne simülatöründe user_id_update. Bilmediğiniz nedenleri kabul edin.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6d",
"object": "event",
"type": "contact.identity_changed",
"api_version": "v1",
"created_at": "2026-10-20T10:00:00.050Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": {
"id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"type": "whatsapp"
},
"test": false,
"data": {
"contact_id": "01j8x7ct5k2m4n6p8q0r2s4t6v",
"channel_id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"previous": {
"type": "bsuid",
"value": "TR.ExampleUser1"
},
"current": {
"type": "bsuid",
"value": "TR.ExampleUser2"
},
"reason": "user_id_update",
"occurred_at": "2026-10-20T10:00:00.000Z"
}
}
contact.consent_changed
Bir izin kaydı eklendi: API ile, STOP, DUR ya da İPTAL yazan kişiyle, WhatsApp'ın pazarlama reddiyle, işletmenin pazarlama mesajlarını WhatsApp'ta durduran kişiyle (source meta_user_preferences; yalnızca pazarlama; WhatsApp'ta yeniden açmak izin değildir: kayıt ve olay yok), UPPU panelinde bir ekip üyesiyle (source agent_recorded) ya da CSV içe aktarmasıyla (source import; yeni her kayıt için bir olay). Olay yazılan kaydı bildirir, kişinin geçerli durumunu değil: daha yeni bir geri çekmeden önce toplanmış izin de kaydedilir ve granted olayı üretir, geri çekme geçerli kalır. Geçerli durumu GET /v1/contacts/{id} yanıtının consents özetinden okuyun. İzin kurallarını UPPU kendisi uygular; olayı kendi listelerinizi güncel tutmak için kullanın.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6e",
"object": "event",
"type": "contact.consent_changed",
"api_version": "v1",
"created_at": "2026-10-20T09:16:00.030Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": {
"id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"type": "whatsapp"
},
"test": false,
"data": {
"contact_id": "01j8x7ct5k2m4n6p8q0r2s4t6v",
"consent": {
"id": "01jab3cn5t2m4n6p8q0r2s4t6v",
"channel_type": "whatsapp",
"purpose": "marketing",
"state": "withdrawn",
"source": "inbound_keyword",
"recorded_at": "2026-10-20T09:16:00.000Z"
}
}
}
contact.erased
UPPU bir kişiyi sildi (örneğin bir kişisel veri başvurusu üzerine). Kişinin sizdeki kopyasını silin ya da anonimleştirin.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6f",
"object": "event",
"type": "contact.erased",
"api_version": "v1",
"created_at": "2026-10-20T11:00:00.000Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": {
"id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"type": "whatsapp"
},
"test": false,
"data": {
"contact_id": "01j8x7ct5k2m4n6p8q0r2s4t6v"
}
}
template.updated
Bir WhatsApp şablonunun durumu, kategorisi ya da kalitesi değişti. PAUSED ya da REJECTED olan şablonu göndermeyi bırakın. Zarfın channel'ı null'dır.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6g",
"object": "event",
"type": "template.updated",
"api_version": "v1",
"created_at": "2026-10-20T08:00:00.000Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": null,
"test": false,
"data": {
"template": {
"object": "template",
"id": "01jab3tp1a2m4n6p8q0r2s4t6v",
"name": "order_update",
"language": "tr",
"category": "UTILITY",
"status": "PAUSED",
"quality": "YELLOW",
"channel_ids": [
"01j9z0ch5k2m4n6p8q0r2s4t6v"
]
},
"change": {
"field": "status",
"previous": "APPROVED",
"current": "PAUSED",
"reason": null
}
}
}
channel.status_changed
Bir kanalın durumu ya da kipi değişti; örneğin bağlandı, duraklatıldı ya da bağlantısı kesildi. reason nedenini söyler (örneğin token_invalid, disconnected, connected); bilmediğiniz nedenleri kabul edin.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6h",
"object": "event",
"type": "channel.status_changed",
"api_version": "v1",
"created_at": "2026-10-20T09:00:00.000Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": {
"id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"type": "whatsapp"
},
"test": false,
"data": {
"channel_id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"status": "paused",
"previous_status": "active",
"mode": "live",
"previous_mode": "live",
"reason": "token_invalid"
}
}
channel.health_changed
Bir kanalın sağlık özeti değişti (green, amber, red, unknown); reasons yeşil olmayan denetimleri listeler.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6j",
"object": "event",
"type": "channel.health_changed",
"api_version": "v1",
"created_at": "2026-10-20T09:00:00.500Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": {
"id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"type": "whatsapp"
},
"test": false,
"data": {
"channel_id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"health": {
"status": "red",
"previous_status": "green",
"reasons": [
"token_invalid"
],
"checked_at": "2026-10-20T09:00:00.000Z"
},
"messaging_limit": "TIER_1K",
"quality": "GREEN"
}
}
conversation.updated
Bir konuşma değişti: onu kimin tuttuğu, durumu ya da ataması. data.conversation konuşmanın o anki hâlidir (GET /v1/conversations/{id}'nin döndürdüğü nesne), data.change neyin değiştiği, data.reason neden ve data.actor kimin yaptığı (type member, anahtarınızın api_key_prefix'iyle api, bot ya da system). Yeni uç noktada bu olay kapalı gelir: ona açıkça abone olun. UPPU onu yalnızca uç noktalarınızdan biri abone olduğu sürece yazar; GET /v1/events'te de yalnızca o zaman bulunur.
handed_over: ekip konuşmayı UPPU Bot'tan ya da sisteminizden aldı: UPPU Bot devretti (reasonbotun devir nedeni, örneğinkeyword), bir temsilci yanıtladı, üstlendi ya da atadı (agent_takeover) ya da sisteminizPOST /v1/conversations/{id}/handoverçağırdı (api).returned_to_botvereleased: konuşma UPPU Bot'a (gelen kutusundan ya daPOST /v1/conversations/{id}/releaseile) ya da sisteminize (api kanalındarelease) döndü.resolved,reopened,assignedveunassigned:reasonnedenini söyler, örneğinmanual(gelen kutusunda bir temsilci),api(anahtarınız),auto(otomatik atama) ya daidle(24 saat etkinliksiz kalınca çözüldü). Atanmış olarak açılan konuşma, ilk mesajınınmessage.received'ından önceassignedgönderir.- Bir eylem birden çok olay gönderebilir, değişikliklerin sırasıyla: devralma önce
handed_over, sonraassignedgönderir. - Bir ekip üyesi ayrılınca ya da çıkarılınca açık konuşmaları
unassignedgönderir (reasonmember_removed,member_left,role_changed,account_deletedya datenant_closed); çözülmüş konuşmaları hiçbir şey göndermez. - Kanalın yönetim kipinin panelde değişmesi olay göndermez, ama kanalın açık konuşmaları onunla el değiştirir: UPPU Bot'a ya da ekip gelen kutusuna geçen api kanalında sisteminizin tuttuğu konuşmalar ekibe geçer (
held_byteam). Yalnızca UPPU Bot'un kanaldan ayrılması botun tuttuğu her konuşma içinhanded_over(bot_detached) gönderir.message.received'dakiconversation.handling(ya da kanalınhandling'i) değişince kanalın açık konuşmalarınıGET /v1/conversations?channel_id=…&status=openile yeniden okuyun. - Atananın kimliği, devir notu ve sizin
reasonilenote'unuz hiçbir zaman yer almaz. Bilmediğiniz değişikliği, nedeni ve aktör türünü kabul edin.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6k",
"object": "event",
"type": "conversation.updated",
"api_version": "v1",
"created_at": "2026-10-20T12:00:00.012Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": {
"id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"type": "whatsapp"
},
"test": false,
"data": {
"conversation": {
"object": "conversation",
"id": "01jab39zcv2m4n6p8q0r2s4t6v",
"channel_id": "01j9z0ch5k2m4n6p8q0r2s4t6v",
"contact_id": "01j8x7ct5k2m4n6p8q0r2s4t6v",
"status": "open",
"handling": "api",
"assigned": false,
"handed_over_at": "2026-10-20T12:00:00.000Z",
"held_by": "team",
"handover_reason": "api",
"opened_at": "2026-10-20T11:55:00.000Z",
"resolved_at": null,
"last_inbound_at": "2026-10-20T11:55:00.000Z",
"last_message_at": "2026-10-20T11:56:00.000Z",
"service_window": {
"open": true,
"closes_at": "2026-10-21T11:53:00.000Z"
}
},
"change": "handed_over",
"reason": "api",
"actor": {
"type": "api",
"api_key_prefix": "k7Hq2mP0aZ1x"
},
"occurred_at": "2026-10-20T12:00:00.000Z"
}
}
contact.reachability_changed
Telegram: kişi botu engelledi ya da engeli kaldırdı ya da Telegram bir gönderimi reddetti. reachable blocked_by_contact ya da send_forbidden ile false, unblocked_by_contact ya da contact_wrote ile true'dur.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6m",
"object": "event",
"type": "contact.reachability_changed",
"api_version": "v1",
"created_at": "2026-10-21T10:00:00.040Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": {
"id": "01j9z0tg5k2m4n6p8q0r2s4t6v",
"type": "telegram"
},
"test": false,
"data": {
"contact_id": "01j8x7ct5k2m4n6p8q0r2s4t6v",
"channel_id": "01j9z0tg5k2m4n6p8q0r2s4t6v",
"identity": {
"type": "telegram",
"value": "123456789"
},
"reachable": false,
"reason": "blocked_by_contact",
"occurred_at": "2026-10-21T10:00:00.000Z"
}
}
contact.updated
Bir kişi değişti: adı, kimlikleri (eklenen ya da yerine yenisi gelen kimlik; örneğin WhatsApp kullanıcı kimliği ya da sitenizin imzaladığı kullanıcı kimliği), firmanın kişi alanları ya da bir birleştirme ve geri alınması. data.contact kişinin o anki hâlidir (GET /v1/contacts/{id}'nin bütün kanallar anahtarına döndürdüğü nesne), data.changes değişen alanlar (display_name, identities, merged_into, notes, attributes; önceki değerler hiçbir zaman), data.reason değişikliğin nedenidir (member_edited, provider_name, pre_chat, identity_added, identity_rotated, signed_handoff, merged ya da merge_reverted). Yeni uç noktada bu olay kapalı gelir: ona açıkça abone olun. UPPU onu yalnızca uç noktalarınızdan biri abone olduğu sürece yazar; GET /v1/events'te de yalnızca o zaman bulunur.
- Bir değişiklik bir olay gönderir; değişmeyen yazım hiçbir şey göndermez. Birleştirme iki kişinin her biri için bir olay gönderir: birleşen kişide
merged_intodolar ve kimliği kalmaz, kalan kişi kimlikleri alır. Birleştirmenin geri alınması da yine her biri için birer olay gönderir. - Yalnızca ekibin notunun değişmesi olay göndermez; her olay güncel notu taşır.
- Kişinin açılışı değişiklik değildir: yeni kişiyi
message.receivedtaşır; sitenizin kullanıcıyı ilk mesajdan önce imzaladığı durumda da. - Sitenizin oturum sırrını yenilemek ya da kapatmak oturum açmış kullanıcıların tarayıcılarının oturumunu kapatır: bu kullanıcıların her kişisi bir olay alır (
signed_handoff), oweb_visitorkimliklericurrent: falseolur. - Zarfın
channel'ınull'dır, çünkü kişinin birden çok kanalda kimliği olabilir. Kişi bütün kanallarındaki kimlikleri taşıdığından kanal süzgeçli uç nokta olayı yalnızca kişinin bütün kimlikleri ve konuşmaları o kanaldaysa alır; birden çok kanalda bulunan kişinin olayı yalnızca kanal süzgeci olmayan uç noktalara gider.GET /v1/eventsonu yalnızca bütün kanallar anahtarına verir. - Engellenmiş kişi için gönderilmez. Bilmediğiniz alanı, değişikliği ve nedeni kabul edin.
- UPPU bu olayı her ortam için açar; açılana kadar yukarıdaki olay tablosu onu «henüz üretilmiyor» diye işaretler: abone olabilirsiniz, hiçbir şey gönderilmez.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6m",
"object": "event",
"type": "contact.updated",
"api_version": "v1",
"created_at": "2026-10-26T12:00:00.012Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": null,
"test": false,
"data": {
"contact": {
"object": "contact",
"id": "01j8x7ct5k2m4n6p8q0r2s4t6v",
"display_name": "Ayşe Yılmaz",
"blocked": false,
"merged_into": null,
"identities": [
{
"channel_id": "01j9z0ch5k2m4n6p8q0r2s4t6w",
"type": "web_visitor",
"value": "wv_01jab3vs5k2m4n6p8q0r2s4t6v",
"current": true
},
{
"channel_id": "01j9z0ch5k2m4n6p8q0r2s4t6w",
"type": "external",
"value": "user-1001",
"current": true
}
],
"service_windows": [],
"consents": [],
"created_at": "2026-10-25T09:30:00.000Z",
"notes": null,
"attributes": {
"customer_no": "A-1001"
}
},
"changes": [
"display_name",
"identities"
],
"reason": "signed_handoff",
"occurred_at": "2026-10-26T12:00:00.000Z"
}
}
account.service_stop_scheduled
UPPU ödemeyi daha önce kaydetmezse firmanın hizmeti faturalandırma nedeniyle data.stop_at anında durur: ödemesi uzun süredir gecikti (reason billing_overdue) ya da aboneliği sona erdi (subscription_ended). UPPU'nun durma uyarısıyla, durmadan en az 72 saat önce gönderilir; durma her zaman bir iş günü Türkiye saatiyle 10:00'dadır. O andan sonra anahtarın IP izin listesini geçen çağıranın her API yanıtı geçerli durma anını UPPU-Service-Stop-At başlığında taşır. An yalnızca ileri kayar: UPPU'nun uyarısı kimseye ulaşmayıp yeniden gönderilirse ikinci bir account.service_stop_scheduled daha geç anı bildirir; başlık her zaman güncel anı taşır.
- Yeni uç noktada varsayılan olarak seçilidir; uç nokta onu olay listesinden çıkarabilir. Listesinde olmayan uç nokta (örneğin seçilebilir olmadan önce açılmış olan) onu listesine eklediğinizde alır. Ona abone her uç noktaya kanal süzgecinden bağımsız gider. Zarfın
channel'ınull. - Hizmet durduğunda her API isteği
403 service_stoppedalır, başka olay gönderilmez ve sırası gelen teslimatlarservice_stoppedile ölü olur. Gelen mesajlar kaydedilmeye devam eder.
{
"id": "01jace0s7p2m4n6p8q0r2s4t6m",
"object": "event",
"type": "account.service_stop_scheduled",
"api_version": "v1",
"created_at": "2026-10-26T07:00:00.012Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": null,
"test": false,
"data": {
"stop_at": "2026-10-29T07:00:00.000Z",
"reason": "billing_overdue",
"occurred_at": "2026-10-26T07:00:00.000Z"
}
}
account.service_resumed
Faturalandırma nedeniyle durmuş hizmet yeniden çalışıyor: stopped_at durduğu, resumed_at yeniden açıldığı an. service_stopped ile ölen teslimatları panelden yeniden gönderin; hiçbir şey kendiliğinden yeniden gönderilmez. account.service_stop_scheduled gibi yeni uç noktada varsayılan olarak seçilidir ve ona abone her uç noktaya kanal süzgecinden bağımsız gider.
{
"id": "01jace0r3s2m4n6p8q0r2s4t6m",
"object": "event",
"type": "account.service_resumed",
"api_version": "v1",
"created_at": "2026-10-30T11:42:10.512Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": null,
"test": false,
"data": {
"stopped_at": "2026-10-29T07:00:00.000Z",
"resumed_at": "2026-10-30T11:42:10.500Z",
"occurred_at": "2026-10-30T11:42:10.500Z"
}
}
webhook.test
Panelin ve API'nin test olayı ve yanlış imzalı denemesi ile haftalık test olayı gönderir, her zaman test: true ile. Saklanmaz ve GET /v1/events'te hiç görünmez.
{
"id": "01jace0e1v2m4n6p8q0r2s4t6n",
"object": "event",
"type": "webhook.test",
"api_version": "v1",
"created_at": "2026-10-20T09:15:02.481Z",
"team_id": "01j8x7tm5k2m4n6p8q0r2s4t6v",
"channel": null,
"test": true,
"data": {
"note": "UPPU test olayı",
"endpoint_id": "01jab3ep5k2m4n6p8q0r2s4t6v"
}
}