İzleme

İmzalı teslimat webhooks'ları

Konsolun Webhooks sayfasında bir HTTPS endpoint'i ayarlayın. Bir mesaj son duruma ulaştığında, bu endpoint'e bir JSON olayı ile bir POST göndeririz.

Olaylar

typeNe zaman
message.deliveredMesaj teslim edildi.
message.failedMesaj başarısız oldu; data.error hata kodunu içerir. Ücreti iade edildi.
POST to your endpointJSON
{
  "id": "evt_8F3K2Q9TZ1MXD",
  "type": "message.delivered",
  "created_at": "2026-11-07T09:30:17.902Z",
  "data": {
    "id": "msg_8F3K2Q9TZ1MX",
    "object": "message",
    "batch_id": "bat_4M7Q1X0PK2RS",
    "to": "+14155550123",
    "country": "US",
    "text": "Your Northwind code is 482913. It expires in 10 minutes.",
    "segments": 1,
    "price": "0.00507",
    "currency": "USD",
    "status": "delivered",
    "error": null,
    "reference": "login-7781",
    "created_at": "2026-11-07T09:30:12.418Z",
    "sent_at": "2026-11-07T09:30:13.020Z",
    "done_at": "2026-11-07T09:30:17.902Z"
  }
}

Başlıklar ve imza

Her çağrı, Standard Webhooks formatında üç başlık taşır:

BaşlıkDeğer
webhook-idOlay kimliği (evt_...). Aynı kimlik, bir olayın her yeniden denemesinde kullanılır.
webhook-timestampBu denemenin imzalandığı Unix zamanı (saniye cinsinden).
webhook-signaturev1, ardından base64 HMAC-SHA256 imzası. Birden fazla imza boşluklarla ayrılmış şekilde listelenebilir: herhangi biri eşleştiğinde çağrıyı kabul edin.

Bir çağrıyı kontrol etmek için: konsoldan gizli anahtarı alın (whsec_ ile başlar), whsec_ sonrası kısmı base64url-decode ederek anahtarı elde edin, webhook-id + "." + webhook-timestamp + "." + raw body için HMAC-SHA256 hesaplayın, base64-encode edin ve imzayla sabit zamanda karşılaştırın. Saatinizden beş dakikadan fazla uzak olan zaman damgalarını reddedin. Her zaman ham gövdeyi kullanın: ayrıştırılıp yeniden serileştirilmiş bir JSON gövdesi eşleşmeyecektir.

// Express: keep the raw body, check the signature, then answer 2xx quickly
import crypto from "node:crypto";
import express from "express";

const app = express();
const secret = process.env.BULKSMSAPI_WEBHOOK_SECRET; // whsec_...

app.post("/hooks/sms", express.raw({ type: "application/json" }), (req, res) => {
  const id = req.header("webhook-id");
  const ts = req.header("webhook-timestamp");
  const key = Buffer.from(secret.slice("whsec_".length), "base64url");
  const expected = crypto.createHmac("sha256", key).update(`${id}.${ts}.${req.body}`).digest("base64");
  const sent = (req.header("webhook-signature") || "").split(" ").map((s) => s.replace(/^v1,/, ""));
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  if (!fresh || !sent.some((s) => s.length === expected.length && crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)))) {
    return res.status(401).end();
  }
  const event = JSON.parse(req.body);
  console.log(event.type, event.data.id, event.data.status);
  res.status(204).end();
});
app.listen(3000);

Yanıtlama ve yeniden denemeler

  • 10 saniye içinde herhangi bir 2xx durumuyla yanıt verin. Yavaş işleri yanıt verdikten sonra bir kuyruktan yapın.
  • Yönlendirmeler takip edilmez: ayarı son adrese yönlendirin.
  • Zaman aşımına uğrayan veya 2xx dışında bir yanıt veren bir çağrı, 30 saniye, 2 dakika, 10 dakika, 30 dakika, 1 saat, 2 saat, 4 saat, 8 saat, 8 saat sonra tekrar denenir: toplam 10 deneme, ilk denemeden yaklaşık 24 saat içinde.
  • Her deneme, HTTP durumu ve geçen süreyle birlikte Webhooks sayfasında listelenir.

Kopyalar ve sıra

Bir olay iki kez gelebilir, örneğin endpoint'iniz kaydetti ancak yanıt kayboldu. webhook-id saklayın ve zaten işlediğiniz kimlikleri atlayın. Farklı mesajlar için olaylar herhangi bir sırada gelebilir; geliş sırasına güvenmek yerine data.status ve data.done_at okuyun.

Endpoint kuralları

  • Yalnızca HTTPS, genel bir ana bilgisayar adında (IP değerleri, localhost veya özel ağlar yok).
  • Gizli anahtar, Webhooks sayfasında herhangi bir zamanda değiştirilebilir; bundan sonra imzalanan çağrılar yeni gizli anahtarı kullanır.
  • Endpoint kaldırıldığında yeni olaylar durur; zaten tamamlanmış mesajlar polling için durumlarını korur.
İmzalı teslimat webhooks'ları | BulkSMSAPI Docs