Siapkan webhook di dasbor, terima pengiriman, dan verifikasi tanda tangan HMAC – dengan contoh untuk curl, Node.js, dan PHP.
Webhook mengirim permintaan HTTP ke server Anda begitu sesuatu terjadi di workspace Anda – misalnya saat sebuah halaman dipublikasikan. Dengan begitu Anda tidak perlu terus bertanya apakah ada yang berubah. Setiap pengiriman ditandatangani agar server Anda bisa membedakan pesan asli dari yang dipalsukan.
Persyaratan
- Pemilik atau admin di workspace – item menu “Webhook” hanya muncul untuk peran-peran ini
- Mulai Creator Pro; di Creator Free tertulis “Webhook tersedia mulai dari Creator Pro.”
- Hingga 5 webhook di Creator Pro, 25 di Creator Agency, 100 di Enterprise (bisa disesuaikan)
- Server yang bisa dijangkau di alamat https publik
Webhook hanya Anda kelola di dasbor. Webhook tidak bisa dibuat atau diubah dengan kunci API.
Membuat webhook
- Buka “Webhook” di navigasi
- Klik “+ Webhook baru”
- Masukkan URL tujuan dan pilih event-nya
- Opsional: masukkan deskripsi dan pilih statusnya
- Klik “Buat webhook”
- Di langkah “Selesai”, salin secret penandatanganan (“Secret penandatanganan – hanya terlihat sekarang”) dan simpan di server Anda – secret ini hanya ditampilkan sekarang
- Uji webhook dengan “Uji”. Hasilnya tetap di kartu sampai pengujian berikutnya: “Berhasil terkirim” atau “Tidak terkirim” dengan kode HTTP (atau “tidak ada respons”), durasi, dan awal responsnya
- “URL tujuan (https://…)”
- Hingga 2048 karakter. Hanya https, tanpa data login di URL, tanpa alamat localhost, dan tanpa nama internal seperti .local, .internal, atau .lan. Nama harus mengarah ke alamat IP publik; LinkHarbor memeriksanya lagi sebelum setiap pengiriman.
- “Event”
- Minimal satu event. Setiap grup punya “Pilih semua” dan “Batalkan semua pilihan”.
- “Deskripsi”
- Opsional, hingga 255 karakter – misalnya, untuk apa webhook ini.
- “Status”
- “Aktif” atau “Nonaktif”. Webhook yang nonaktif tidak menerima pengiriman.
Event
| Event | Di dasbor | Kapan | Isi data |
|---|---|---|---|
| page.published | Halaman dipublikasikan | Sebuah halaman dipublikasikan – di dasbor, lewat API, atau oleh asisten AI | page_id, version, checksum, published_by_user_id (null untuk kunci API dan asisten AI) |
| form.submitted | Formulir dikirim | Pengunjung mengirim formulir di salah satu halaman Anda | form_id, form_name, submission_id, page_id, block_id, submitted_at, values (kunci kolom → nilai), consent (kunci persetujuan → true/false) |
| domain.verified | Domain diverifikasi | Domain kustom berhasil diverifikasi | domain_id, hostname, verification_method, status |
| domain.disabled | Domain dinonaktifkan | Domain kustom dinonaktifkan di dasbor (bukan karena downgrade) | domain_id, hostname, status |
| webhook.test | – (tombol “Uji”) | Anda mengeklik “Uji” | message (catatan dalam bahasa akun orang yang memulai pengujian; jangan mencocokkan dengannya) |
form.submitted berisi nilai persis seperti yang dikirim pengunjung, tetapi tidak pernah alamat IP atau browser mereka. Pengiriman berjalan di latar belakang: pengunjung tidak menunggunya, dan pengiriman yang gagal tidak menghalangi kiriman formulir.
Susunan sebuah pengiriman
LinkHarbor mengirim setiap pengiriman sebagai POST dengan body JSON dan header-header ini:
| Header | Isi |
|---|---|
| Content-Type | application/json |
| X-LinkHarbor-Event | Nama event, misalnya page.published |
| X-LinkHarbor-Delivery-Id | ID unik pengiriman ini (UUID), sama dengan id di body |
| X-LinkHarbor-Timestamp | Waktu pengiriman dalam detik Unix |
| X-LinkHarbor-Signature | sha256= diikuti tanda tangan HMAC-SHA256 dalam hex |
| X-LinkHarbor-Signature-Version | v1 |
{
"id": "3f1c2a9e-8d4b-4a51-9f0e-6b7c1d2e3f40",
"event": "page.published",
"created_at": "2026-11-01T09:30:12+00:00",
"data": {
"page_id": 42,
"version": 8,
"checksum": "9b1e5c…",
"published_by_user_id": 7
}
} Pengiriman ulang mendapat id baru ditambah kolom redelivery_of (ID pengiriman yang diulang) dan delivery_root (ID pengiriman pertama dalam rangkaian ini).
Memverifikasi tanda tangan
Setiap webhook punya secret penandatanganan sendiri (32 karakter hex). Anda melihatnya tepat satu kali: di langkah terakhir saat membuat webhook dan tepat setelah “Secret ↺”. Segera salin ke server Anda – LinkHarbor tidak menampilkannya lagi nanti. LinkHarbor memakainya untuk menghitung tanda tangan seperti ini:
- Susun pesannya: timestamp, titik, ID pengiriman, titik, body mentah – yaitu timestamp.delivery_id.body
- Hitung HMAC-SHA256 atas pesan ini dengan secret penandatanganan sebagai kunci
- Kirim hasilnya sebagai string hex dengan awalan sha256=
Server Anda sebaiknya memeriksa tanda tangan dengan perbandingan waktu konstan, menolak pengiriman dengan timestamp lebih tua dari 300 detik, dan menyimpan ID pengiriman minimal selama itu untuk mengenali pengulangan. Penting: yang ditandatangani adalah body mentah, persis seperti yang datang – bukan JSON yang Anda enkode ulang.
import crypto from 'node:crypto';
import express from 'express';
const app = express();
const SECRET = process.env.LH_WEBHOOK_SECRET;
const seen = new Set(); // di produksi: database atau Redis dengan masa berlaku
app.post('/webhooks/linkharbor', express.raw({ type: 'application/json' }), (req, res) => {
const ts = req.get('X-LinkHarbor-Timestamp') || '';
const id = req.get('X-LinkHarbor-Delivery-Id') || '';
const sig = req.get('X-LinkHarbor-Signature') || '';
if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) {
return res.status(400).send('timestamp');
}
const expected = 'sha256=' + crypto
.createHmac('sha256', SECRET)
.update(ts + '.' + id + '.')
.update(req.body) // body mentah sebagai Buffer
.digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(sig);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).send('signature');
}
const event = JSON.parse(req.body.toString('utf8'));
const key = event.delivery_root || event.id; // kenali pengiriman ulang dari rangkaian yang sama
if (!seen.has(key)) {
seen.add(key);
// proses di sini, sebaiknya secara asinkron di antrean
}
res.sendStatus(200);
});
app.listen(3000); <?php
$secret = getenv('LH_WEBHOOK_SECRET');
$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_LINKHARBOR_TIMESTAMP'] ?? '';
$id = $_SERVER['HTTP_X_LINKHARBOR_DELIVERY_ID'] ?? '';
$sig = $_SERVER['HTTP_X_LINKHARBOR_SIGNATURE'] ?? '';
if (!ctype_digit($ts) || abs(time() - (int)$ts) > 300) {
http_response_code(400);
exit('timestamp');
}
$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $id . '.' . $body, $secret);
if (!hash_equals($expected, $sig)) {
http_response_code(401);
exit('signature');
}
$event = json_decode($body, true);
// Kenali pengiriman ganda lewat $event['delivery_root'] ?? $event['id'],
// lalu proses.
http_response_code(200); Menguji endpoint Anda dengan curl
Skrip ini mengirim pengiriman uji yang ditandatangani dengan benar ke server Anda sendiri – praktis sebelum Anda membuat webhook di LinkHarbor:
SECRET="your-signing-secret"
URL="https://example.com/webhooks/linkharbor"
TS=$(date +%s)
ID=$(uuidgen | tr 'A-Z' 'a-z')
BODY='{"id":"'"$ID"'","event":"webhook.test","created_at":"2026-11-01T09:30:12+00:00","data":{"message":"Ini adalah event tes untuk webhook ini."}}'
SIG="sha256=$(printf '%s' "$TS.$ID.$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')"
curl -X POST "$URL" \
-H "Content-Type: application/json" \
-H "X-LinkHarbor-Event: webhook.test" \
-H "X-LinkHarbor-Delivery-Id: $ID" \
-H "X-LinkHarbor-Timestamp: $TS" \
-H "X-LinkHarbor-Signature: $SIG" \
-H "X-LinkHarbor-Signature-Version: v1" \
-d "$BODY" Respons, batas waktu, dan pengiriman ulang
- Setiap respons dengan status 2xx dianggap berhasil; pengalihan (3xx) tidak diikuti
- Server Anda punya waktu 10 detik untuk merespons, dan paling lama 5 detik untuk membangun koneksi
- Semua webhook untuk satu event berbagi total 25 detik; yang belum mendapat giliran sampai saat itu ditandai gagal dan bisa dikirim ulang
- LinkHarbor tidak mengulangi pengiriman yang gagal secara otomatis
- Anda bisa mengirim ulang pengiriman yang gagal secara manual, tetapi tidak yang sejak itu sudah berhasil. Pengiriman ulang punya id baru dan created_at baru
- Paling banyak 3 percobaan diizinkan per event, termasuk pengiriman pertama; setelah itu event masuk ke “Dead letter” dan tidak bisa dikirim ulang lagi
Pengiriman di dasbor
“Pengiriman” membuka log sebuah webhook. Log ini punya tiga tab:
- “Semua pengiriman”
- Semua pengiriman, dengan filter untuk event, status (“Berhasil (2xx)”, “Kesalahan klien (4xx)”, “Kesalahan server (5xx)”, “Gagal”), dan “Batas”. “↺ Coba lagi” mengirim ulang pengiriman yang gagal, selama belum ada pengiriman berikutnya yang berhasil. Mengeklik sebuah baris menampilkan permintaan, respons, body, dan JSON mentah.
- “Replay”
- Rangkaian pengiriman ulang dengan hasil “Pulih” atau “Masih gagal” dan jumlah percobaannya.
- “Dead letter”
- Pengiriman yang semua percobaan yang diizinkan gagal – pengiriman pertama dan pengiriman ulang bersama-sama. Tab ini hanya untuk dilihat: pengiriman ini tidak bisa dikirim ulang lagi. Periksa endpoint Anda; event baru lalu dikirim seperti biasa. Jika Anda memerlukan datanya, ambil lewat API.
Jika pengiriman ulang tidak berhasil, dasbor menyebutkan alasannya:
- “Tidak dikirim ulang: event ini sudah gagal … kali, tidak ada percobaan lagi yang bisa dilakukan. Anda bisa menemukannya di ‘Dead letter’.”
- Semua 3 percobaan sudah habis.
- “Tidak dikirim ulang: event ini sudah berhasil dikirim sejak itu.”
- Pengiriman berikutnya dalam rangkaian yang sama sudah berhasil.
Verifikasi di dasbor
Di “Verifikasi” Anda menemukan dua alat bantu:
- “Kit verifikasi”
- “Muat kit” menampilkan algoritme, nama header, format pesan yang ditandatangani, dan toleransi yang disarankan sebesar 300 detik. Secret-nya sendiri tidak disertakan.
- “Verifikasi tanda tangan”
- Masukkan ID pengiriman, timestamp, tanda tangan, dan body permintaan mentah dari pengiriman yang Anda terima. LinkHarbor lalu menyatakan “Tanda tangan valid” atau “Tanda tangan tidak valid”. Salin timestamp dan tanda tangan dari header X-LinkHarbor-Timestamp dan X-LinkHarbor-Signature. Pemeriksaan ini hanya berfungsi untuk pengiriman dari 5 menit terakhir; untuk yang lebih lama, hasilnya “Tanda tangan tidak valid” meskipun tanda tangannya benar.
Merotasi secret, menonaktifkan, menghapus
- “Secret ↺” membuat secret penandatanganan baru dan menampilkannya sekali; yang lama langsung berhenti berfungsi, dan server Anda harus memakai yang baru
- Di “Edit”, setel status ke “Nonaktif” untuk menjeda pengiriman
- Ikon tempat sampah menghapus webhook; sampai Anda menutup pesannya, Anda bisa membatalkan dengan “Urungkan”
Saat Anda pindah ke paket yang lebih kecil, webhook di atas batas baru dinonaktifkan, dan di Creator Free semuanya. Webhook-webhook itu tetap tersimpan; setelah upgrade, LinkHarbor otomatis mengaktifkan kembali webhook yang dinonaktifkan hingga batas paket baru – termasuk yang Anda nonaktifkan sendiri.
Mungkin ini juga berguna
Tidak menemukan jawabannya?
Beri tahu kami apa yang Anda perlukan, dan tim dukungan kami akan membantu Anda secara langsung.