CuanTuanDokumentasi

Webhook

CuanTuan menolak setiap penghantaran borang ke URL anda, ditandatangani supaya anda boleh membuktikan ia benar-benar daripada kami.

Webhook berjalan ke arah BERTENTANGAN dengan API. API: anda menarik dari kami dengan kunci. Webhook: kami menolak kepada anda, ditandatangani dengan rahsia yang dijana semasa integrasi disimpan. Ia tidak memerlukan kunci API dan tidak mengambil kuota had kadar.

Memasangnya

Panel admin → Formulir Data → pilih borang → Integrasi. Masukkan URL penerima anda dan simpan; rahsia tandatangan dijana pada masa itu dan dipaparkan sekali.

Bentuk permintaan

Setiap penghantaran borang dihantar sebagai POST JSON dengan pengepala ini:

PengepalaIsi
X-CuanTuan-Signaturet=<unix>,v1=<hmac-sha256 hex>
X-CuanTuan-Delivery-IdId event. Sama pada setiap cubaan semula — gunakannya untuk nyahduplikasi.
X-CuanTuan-Submission-IdId penghantaran borang.
X-CuanTuan-Form-IdId borang.

Mengesahkan tandatangan

Tandatangan dikira ke atas rentetan <t>.<badan mentah> menggunakan HMAC-SHA256 dengan rahsia integrasi anda.

Node.js
import crypto from "node:crypto";

export function sahkan(badanMentah, pengepala, rahsia) {
  const bahagian = Object.fromEntries(
    pengepala.split(",").map((p) => p.split("=").map((x) => x.trim()))
  );
  const t = Number(bahagian.t);
  if (!Number.isFinite(t)) return false;

  // 1. Tolak permintaan lama. Tanpa ini, seseorang yang merakam satu
  //    permintaan sah boleh memainkannya semula bertahun kemudian.
  if (Math.abs(Math.floor(Date.now() / 1000) - t) > 300) return false;

  // 2. Kira semula ke atas BADAN MENTAH — bukan objek yang sudah dihurai.
  //    JSON.stringify(JSON.parse(x)) tidak semestinya sama dengan x.
  const jangkaan = crypto
    .createHmac("sha256", rahsia)
    .update(`${t}.${badanMentah}`)
    .digest("hex");

  // 3. Bandingkan dalam masa TETAP. Perbandingan === bocor melalui masa.
  const a = Buffer.from(jangkaan, "hex");
  const b = Buffer.from(String(bahagian.v1 || ""), "hex");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Ketiga-tiga langkah itu perlu. Melangkau semakan masa membenarkan main semula; menghurai JSON dahulu memecahkan tandatangan pada aksara yang tidak setara; membandingkan dengan === membocorkan tandatangan sebenar melalui masa tindak balas.

Cubaan semula dan nyahduplikasi

Penghantaran yang gagal dicuba semula. Setiap cubaan membawa X-CuanTuan-Delivery-Id yang sama, jadi simpan id itu dan abaikan yang sudah dilihat — kalau tidak, satu penghantaran borang menjadi dua baris dalam helaian kerja anda.

Yang TIDAK dihantar

  • Alamat IP penghantar.
  • Mana-mana jawapan yang tidak ditanda secara eksplisit dalam pemetaan medan.

Ini keputusan privasi, bukan kelalaian: destinasi seperti helaian kerja berkongsi selalunya dilihat lebih ramai orang daripada panel admin.