Penjejakan

Webhooks penghantaran dengan tandatangan

Tetapkan endpoint HTTPS pada halaman Webhooks konsol. Apabila mesej mencapai status akhir, kami menghantar satu POST dengan peristiwa JSON ke endpoint tersebut.

Peristiwa

typeBila
message.deliveredMesej telah dihantar.
message.failedMesej gagal; data.error mengandungi kod. Harganya telah dikembalikan.
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"
  }
}

Header dan tandatangan

Setiap panggilan membawa tiga header, dalam format Standard Webhooks:

HeaderNilai
webhook-idID acara (evt_...). ID yang sama digunakan untuk setiap percubaan semula bagi satu acara.
webhook-timestampMasa Unix dalam saat apabila percubaan ini ditandatangani.
webhook-signaturev1, diikuti dengan tandatangan base64 HMAC-SHA256. Beberapa tandatangan mungkin disenaraikan, dipisahkan oleh ruang: terima panggilan apabila mana-mana satu padan.

Untuk memeriksa panggilan: ambil rahsia dari konsol (yang bermula dengan whsec_), base64url-decode bahagian selepas whsec_ untuk mendapatkan kunci, kira HMAC-SHA256 bagi webhook-id + "." + webhook-timestamp + "." + raw body, base64-encode dan bandingkan dengan tandatangan dalam masa tetap. Tolak cap masa yang lebih daripada lima minit dari jam anda. Sentiasa gunakan badan mentah: badan JSON yang dihurai dan diserial semula tidak akan sepadan.

// 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);

Jawapan dan percubaan semula

  • Jawab dengan status 2xx dalam masa 10 saat. Lakukan kerja perlahan selepas menjawab, dari barisan.
  • Pengalihan tidak diikuti: arahkan tetapan ke alamat akhir.
  • Panggilan yang tamat masa atau menjawab selain daripada 2xx akan dicuba semula selepas 30 saat, 2 minit, 10 minit, 30 minit, 1 jam, 2 jam, 4 jam, 8 jam, 8 jam: 10 percubaan secara keseluruhan, kira-kira 24 jam dari yang pertama.
  • Setiap percubaan disenaraikan pada halaman Webhooks dengan status HTTP dan masa yang diambil.

Duplikat dan susunan

Acara boleh tiba dua kali, contohnya apabila endpoint anda menyimpannya tetapi jawapannya hilang. Simpan webhook-id dan langkau id yang telah anda uruskan. Acara untuk mesej yang berbeza boleh tiba dalam sebarang susunan; baca data.status dan data.done_at daripada bergantung pada susunan ketibaan.

Peraturan endpoint

  • HTTPS sahaja, pada nama hos awam (tiada literal IP, localhost atau rangkaian persendirian).
  • Rahsia boleh diganti pada halaman Webhooks pada bila-bila masa; panggilan yang ditandatangani selepas itu menggunakan rahsia baru.
  • Membuang endpoint menghentikan acara baru; mesej yang telah selesai mengekalkan status mereka untuk pengundian.
Webhooks penghantaran dengan tandatangan | Dokumen BulkSMSAPI