API v2 (beta)
Webhook'lar
Webhook uç noktası, bir mesajla ilgili bir şey olduğunda WbizTool'un çağırdığı, sunucunuzdaki bir URL'dir: mesaj gönderildi, başarısız oldu, iptal edildi veya süresi doldu. Sürekli sorgulamak yerine haberi anında alırsınız ve her istek imzalıdır; böylece isteğin WbizTool'dan geldiğini doğrulayabilirsiniz.
| İşlem | Endpoint | Kapsam |
|---|---|---|
| Bir uç nokta ekleyin | POST /api/v2/webhooks | messages:read |
| Uç noktaları listeleyin | GET /api/v2/webhooks | messages:read |
| Bir uç noktayı alın | GET /api/v2/webhooks/{id} | messages:read |
| Bir uç noktayı kaldırın | DELETE /api/v2/webhooks/{id} | messages:read |
| Yeni bir imzalama gizli anahtarı alın | POST /api/v2/webhooks/{id}/rotate-secret | messages:read |
| Test olayı gönderin | POST /api/v2/webhooks/{id}/test | messages:read |
Uç noktalar çalışma alanına aittir ve onları neyin gönderdiğinden bağımsız olarak çalışma alanının tüm mesajları için olay alır: API, panel, kampanyalar, hatırlatıcılar veya entegrasyonlar. Bu yüzden bazı numaralarla sınırlı bir anahtar onları yönetemez: her çağrı 403 number_not_allowed yanıtını verir.
Olaylar#
| Tür | Ne zaman |
|---|---|
message.sent | Bir mesaj numaranızdan gönderildi. |
message.failed | Bir mesaj gönderilemedi; nedenini error.message söyler. |
message.cancelled | Bekleyen bir mesaj iptal edildi: API ile, panelden veya numarası ya da kampanyası kaldırıldığı için. |
message.expired | Bir mesaj expires_at zamanından önce gönderilemedi. |
ping | İstediğiniz bir test olayı. |
Numaralar (bağlandı, oturumu kapatıldı) ve gelen mesajlar için olaylar daha sonra gelecek. İletildi ve okundu tikleri olay göndermez; bunları görmek için mesajı alın.
Bir uç nokta ekleyin#
https://wbiztool.com/api/v2/webhooksGövde: JSON (application/json)
Gövde
urlstringzorunluUç noktanız: en fazla 500 karakterlik, herkese açık bir
https://adresi.http://, özel ve yerel adresler (localhostveya192.168.x.xgibi) reddedilir.eventsarray of stringsisteğe bağlıUç noktanın aldığı olay türleri:
message.sent,message.failed,message.cancelledvemessage.expiredtürlerinden herhangi biri. Varsayılan: dördü de.ping, istediğinizde her zaman gelir.descriptionstringisteğe bağlıKendiniz için en fazla 100 karakterlik bir not, örneğin
Order system.
Bir çalışma alanında en fazla 5 uç nokta olabilir. Yanıt 201'dir ve uç noktayı ve onun imzalama secret değerini yalnızca bu kez gösterir. Bunu alıcınızın okuyabileceği bir yerde saklayın, örneğin bir ortam değişkeninde. Sonraki yanıtlar yalnızca secret_last4 gösterir; gizli anahtarı kaybederseniz yenisini alın.
curl -X POST https://wbiztool.com/api/v2/webhooks \
-H "Authorization: Bearer $WBIZTOOL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/wbiztool/events",
"events": ["message.sent", "message.failed"],
"description": "Order system"
}'import os
import requests
response = requests.post(
"https://wbiztool.com/api/v2/webhooks",
headers={"Authorization": f"Bearer {os.environ['WBIZTOOL_API_KEY']}"},
json={
"url": "https://example.com/wbiztool/events",
"events": ["message.sent", "message.failed"],
"description": "Order system",
},
timeout=30,
)
endpoint = response.json()
print("Store this secret now:", endpoint["secret"])// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v2/webhooks", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.WBIZTOOL_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
url: "https://example.com/wbiztool/events",
events: ["message.sent", "message.failed"],
description: "Order system",
}),
});
const endpoint = await response.json();
console.log("Store this secret now:", endpoint.secret);<?php
$ch = curl_init('https://wbiztool.com/api/v2/webhooks');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('WBIZTOOL_API_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'url' => 'https://example.com/wbiztool/events',
'events' => ['message.sent', 'message.failed'],
'description' => 'Order system',
]),
CURLOPT_RETURNTRANSFER => true,
]);
$endpoint = json_decode(curl_exec($ch), true);
curl_close($ch);
echo 'Store this secret now: ' . $endpoint['secret'];Yanıt (201):
{
"id": 41,
"url": "https://example.com/wbiztool/events",
"description": "Order system",
"events": ["message.sent", "message.failed"],
"secret_last4": "9c1e",
"active": true,
"disabled_reason": null,
"created_at": "2026-10-18T11:20:05.733Z",
"last_delivery": null,
"secret": "3f0b…9c1e"
}
Gerçek secret 64 onaltılık karakterden oluşur. Bu isteği aynı Idempotency-Key ile yeniden denemek ikinci bir uç nokta eklemez ve yanıtında gizli anahtar yer almaz.
Uç nokta eklerken oluşan hatalar#
| HTTP | Kod | Ne zaman |
|---|---|---|
400 | validation_failed | url eksik veya çok uzun, events boş veya bilinmeyen bir tür içeriyor ya da bir alan bilinmiyor |
403 | webhook_limit_reached | Çalışma alanında zaten 5 uç nokta var |
403 | number_not_allowed | Anahtar bazı numaralarla sınırlı |
422 | invalid_webhook_url | url herkese açık bir https:// adresi değil |
Uç noktaları listeleyin#
https://wbiztool.com/api/v2/webhooksÇalışma alanının olay alan uç noktaları, en eskiden başlayarak, tek bir data listesinde.
curl https://wbiztool.com/api/v2/webhooks \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"
Liste, durmuş uç noktaları içermez. Sahipler uç noktaları Ayarlar → API anahtarları sayfasında Webhook uç noktaları altında da görür ve kaldırabilir.
Bir uç noktayı alın#
https://wbiztool.com/api/v2/webhooks/{id}Tek bir uç nokta. last_delivery, en son teslimatın nasıl gittiğini gösterir. Mevcut olmayan veya kaldırılmış bir uç nokta 404 webhook_not_found yanıtını verir; durmuş bir uç nokta active: false ile gösterilir.
Bir uç noktayı kaldırın#
https://wbiztool.com/api/v2/webhooks/{id}Uç noktaya artık hiçbir şey gönderilmez; bekleyen yeniden denemeler de buna dahildir. Yanıt {"id": 41, "deleted": true} olur.
Yeni bir imzalama gizli anahtarı alın#
https://wbiztool.com/api/v2/webhooks/{id}/rotate-secretUç nokta için yeni bir gizli anahtar oluşturur. Yanıt 200'dür ve uç noktayı ve yalnızca bu kez gösterilen yeni secret değerini içerir. Eski gizli anahtar hemen çalışmaz hâle gelir: bundan sonra gönderilen olaylar, önceki olayların yeniden denemeleri dahil, yeni anahtarla imzalanır. Alıcınızı hemen güncelleyin.
curl -X POST https://wbiztool.com/api/v2/webhooks/41/rotate-secret \
-H "Authorization: Bearer $WBIZTOOL_API_KEY"
Test olayı gönderin#
https://wbiztool.com/api/v2/webhooks/{id}/testAlıcınızı test edebilmeniz için bu uç noktaya, her olay gibi imzalanmış bir ping olayını kuyruğa alır. Yanıt 202'dir:
{ "event_id": "evt_8a2f4c1d9b7e6a5f4c3b2a19", "type": "ping", "queued": true }
Uç noktanız şunu alır:
{
"id": "evt_8a2f4c1d9b7e6a5f4c3b2a19",
"type": "ping",
"created_at": "2026-10-18T11:21:40.002Z",
"data": { "webhook_id": 41 }
}
Olay yükü#
Her olay, JSON gövdeli bir POST isteğidir:
{
"id": "evt_c41d7e2a9f3b8c6d5e4f3a21",
"type": "message.sent",
"created_at": "2026-10-18T10:15:09.912Z",
"data": {
"message": {
"id": 9817263,
"status": "sent",
"from": { "id": 101, "phone": "919800000000", "platform": "whatsapp" },
"to": { "phone": "+919876543210", "contact_id": 991 },
"text": "Hi Asha, your order #1042 is ready.",
"media": null,
"send_at": null,
"expires_at": null,
"created_at": "2026-10-18T10:15:02.311Z",
"sent_at": "2026-10-18T10:15:09.870Z",
"error": null
}
}
}
| Alan | Açıklama |
|---|---|
id | Olayın ID'si: evt_ ve 24 karakter. Aynı olay her yeniden denemede ID'sini korur. |
type | Olay türlerinden biri. |
created_at | Olayın ne zaman gerçekleştiği. |
data.message | message.* olayları için: o anki hâliyle Message. İçindeki bir media.url en az 26 saat çalışır. |
data.webhook_id | ping için: uç noktanın ID'si. |
Başlıklar:
| Başlık | Değer |
|---|---|
Content-Type | application/json |
User-Agent | WbizTool-Webhooks/2 |
WbizTool-Event-Id | Olayın id değeri; her yeniden denemede aynıdır |
WbizTool-Timestamp | Bu denemenin gönderildiği zaman, Unix saniyesi olarak, örneğin 1792310409 |
WbizTool-Signature | v1= ve uç noktanın gizli anahtarıyla <timestamp>.<raw body> üzerinden hesaplanan onaltılık HMAC-SHA256 |
Webhook imzasını doğrulayın#
Her isteğe güvenmeden önce kontrol edin: imzayı ham gövdeden (framework'ünüz JSON'u ayrıştırmadan önce) hesaplayın, başlıkla sabit sürede karşılaştırın ve eski bir isteğin yeniden oynatılamaması için 5 dakikadan fazla sapan zaman damgalarını reddedin. Bu, uç noktanın kendi gizli anahtarıyla, API v1'in webhook imzalarıyla aynı yöntemdir.
Ardından tekrarları atmak için WbizTool-Event-Id kullanın: aynı olay birden fazla kez gelebilir, örneğin yanıtınız kaybolduğunda ve yeniden denediğimizde.
import hashlib, hmac, json, os, time
SECRET = os.environ["WBIZTOOL_WEBHOOK_SECRET"]
def verify(secret: str, body: bytes, headers) -> bool:
ts, sig = headers.get("WbizTool-Timestamp", ""), headers.get("WbizTool-Signature", "")
if not ts.isdigit() or abs(time.time() - int(ts)) > 300:
return False
mac = "v1=" + hmac.new(secret.encode(), ts.encode() + b"." + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(mac, sig)
# Flask
from flask import Flask, request
app = Flask(__name__)
seen = set() # use your database in production
@app.post("/wbiztool/events")
def events():
body = request.get_data() # the raw bytes
if not verify(SECRET, body, request.headers):
return "", 401
event_id = request.headers["WbizTool-Event-Id"]
if event_id in seen:
return "", 200 # a repeat: already handled
seen.add(event_id)
event = json.loads(body)
if event["type"] == "message.failed":
message = event["data"]["message"]
print("Failed:", message["id"], message["error"]["message"])
return "", 200Django'da request.body ve request.headers değerlerini verin.
const crypto = require("crypto");
const express = require("express");
const SECRET = process.env.WBIZTOOL_WEBHOOK_SECRET;
function verify(secret, rawBody, headers) {
const ts = String(headers["wbiztool-timestamp"] || ""), sig = String(headers["wbiztool-signature"] || "");
if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const mac = "v1=" + crypto.createHmac("sha256", secret).update(ts + ".").update(rawBody).digest("hex");
return sig.length === mac.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(mac));
}
const app = express();
const seen = new Set(); // use your database in production
// express.raw keeps the body as a Buffer: the signature covers the exact bytes.
app.post("/wbiztool/events", express.raw({ type: "*/*" }), (req, res) => {
if (!verify(SECRET, req.body, req.headers)) return res.sendStatus(401);
const eventId = req.headers["wbiztool-event-id"];
if (seen.has(eventId)) return res.sendStatus(200); // a repeat: already handled
seen.add(eventId);
const event = JSON.parse(req.body);
if (event.type === "message.failed") {
const message = event.data.message;
console.log("Failed:", message.id, message.error.message);
}
res.sendStatus(200);
});
app.listen(3000);Hızlıca 2xx ile yanıt verin, yavaş işleri sonra yapın (örneğin bir kuyrukta).
Yeniden denemeler#
- 10 saniye içinde herhangi bir
2xxile yanıt verin. Bunun dışındaki her şey başarısızlıktır: başka bir durum kodu (4xxdahil), 10 saniye içinde yanıt gelmemesi veya 3 saniye içinde bağlantı kurulamaması. Yönlendirmeler en fazla 3 kez izlenir ve her biri herkese açık bir adrese gitmelidir. - Başarısız bir teslimat yeniden denenir: 1, 5 ve 15 dakika, ardından 1, 2, 4, 8 ve 8 saat sonra; yaklaşık 23 saat boyunca 9 deneme. Sonuncusundan sonra o olay atılır.
- Yeniden deneme aynı gövdeye ve
WbizTool-Event-Iddeğerine, yeni birWbizTool-Timestampve imzaya sahiptir. - Sıra garanti edilmez. Yeniden denenen bir
message.sent, daha sonraki bir olaydan sonra gelebilir. Sıra önemliyse mesajınstatusdeğerini kullanın veya mesajı alın.
Uç noktadaki last_delivery, en son teslimatın nasıl gittiğini gösterir: state (pending, delivered veya failed), sunucunuzun verdiği status_code ve olayın ne zaman oluşturulduğu.
Uç noktalar ne zaman durur#
Bir uç nokta, aşağıdakilerden biri olduğunda olay almayı bırakır. Nedenini görebilmeniz için active: false ve bir disabled_reason ile GET /webhooks içinde kalır; hâlâ okunabilir ve kaldırılabilir, ancak test edilemez veya yeni bir gizli anahtar verilemez (404).
- 24 saattir başarısız oluyor. Teslimatları başarısız olmaya devam ederken 24 saat boyunca ona hiçbir şey teslim edilemediyse kapatılır ve bekleyen yeniden denemeleri atılır. Ayarlar → API anahtarları sayfası onu Kapalı olarak gösterir. Sunucunuzu düzeltin, ardından uç noktayı yeniden ekleyin.
- Onu oluşturan anahtar iptal edildi veya süresi doldu. Bir anahtarı iptal etmek, onunla kurulan her şeyi durdurur. Uç noktayı başka bir anahtarla yeniden ekleyin.
- Kaldırıldı: Bir uç noktayı kaldırın ile veya Ayarlar → API anahtarları sayfasında.
Durmuş uç noktalar 5 sınırına dahil edilmez.
Webhook uç noktası nesnesi#
| Alan | Tür | Açıklama |
|---|---|---|
id | integer | Uç noktanın ID'si. |
url | string | Olayların gönderildiği yer. |
description | string | Notunuz; yoksa "". |
events | array | Uç noktanın aldığı olay türleri. |
secret | string | İmzalama gizli anahtarı: yalnızca Bir uç nokta ekleyin ve Yeni bir imzalama gizli anahtarı alın yanıtlarında. |
secret_last4 | string | Gizli anahtarın son 4 karakteri; hangisine sahip olduğunuzu anlamak için. |
active | boolean | Artık olay almıyorsa false – bkz. Uç noktalar ne zaman durur. |
disabled_reason | string or null | Neden durduğu (24 saattir başarısız olması veya onu oluşturan anahtarın iptal edilmesi ya da süresinin dolması); etkinken null. |
created_at | string | Ne zaman eklendiği. |
last_delivery | object or null | Denenen en son teslimat: state, status_code (sunucunuz yanıt vermediyse null) ve created_at. İlk teslimattan önce null. |
İlgili sayfalar#
- Mesajlar:
data.messageiçindeki Message nesnesi - API v1 için webhook imzaları
- Hatalar
