Lewati ke konten
Dukungan

Webhook

Webhook memungkinkan Anda menerima notifikasi waktu nyata saat ada peristiwa yang terjadi di akun LabelGrid Anda. Gunakan webhook untuk mengotomatiskan alur kerja dan berintegrasi dengan sistem eksternal.

Untuk Pengembang: Anda juga dapat mengelola webhook secara terprogram melalui API. Lihat Dokumentasi API LabelGrid untuk endpoint dan contohnya.

  1. Anda mengonfigurasi webhook - Tentukan URL dan peristiwa apa saja yang ingin didengarkan
  2. Sebuah peristiwa terjadi - Misalnya, sebuah rilis dikirimkan ke toko
  3. LabelGrid mengirim permintaan POST - Server Anda menerima data peristiwa tersebut
  4. Sistem Anda memprosesnya - Otomatiskan alur kerja berdasarkan peristiwa tersebut

  1. Klik ikon profil Anda di pojok kanan atas
  2. Pilih Webhooks dari menu turun

  1. Klik Create Webhook
  2. Masukkan Name untuk menandai webhook ini
  3. Masukkan URL tempat Anda ingin menerima notifikasi
  4. Pilih Events mana yang akan memicu webhook ini
  5. Klik Create

Saat membuat webhook, Anda akan menerima sebuah secret key. Gunakan ini untuk memverifikasi bahwa permintaan yang masuk benar-benar berasal dari LabelGrid:

  • Simpan secret dengan aman
  • Verifikasi signature pada permintaan yang masuk
  • Jika bocor, buat ulang secret-nya

Konfigurasikan webhook Anda untuk mendengarkan peristiwa berikut. Event Identifier adalah nilai yang akan Anda lihat pada properti event di payload dan pada header X-Webhook-Event:

Event IdentifierDeskripsi
delivery.completedDipicu saat sebuah rilis berhasil dikirimkan ke sebuah outlet
delivery.failedDipicu saat pengiriman ke sebuah outlet gagal
takedown.completedDipicu saat permintaan takedown selesai
release.review.status_changedDipicu saat status peninjauan sebuah rilis berubah
release.distributedDipicu saat sebuah rilis didistribusikan
payment.statement_readyDipicu saat laporan pembayaran siap untuk dilihat

Anda dapat memilih beberapa peristiwa untuk satu webhook, atau membuat webhook terpisah untuk jenis peristiwa yang berbeda.


Daftar webhook menampilkan:

KolomDeskripsi
NameNama webhook yang Anda tetapkan
URLTempat notifikasi dikirim
EventsJumlah peristiwa yang dikonfigurasi
StatusActive atau Inactive
Success / FailJumlah pengiriman yang berhasil dan gagal
Last TriggeredKapan webhook terakhir kali dipanggil
  1. Klik tindakan Edit pada baris webhook
  2. Ubah nama, URL, atau peristiwa
  3. Klik Save

Alihkan status aktif webhook tanpa menghapusnya:

  • Active - Webhook akan menerima notifikasi
  • Inactive - Webhook dijeda, tidak ada notifikasi yang dikirim
  1. Klik tindakan Delete pada baris webhook
  2. Konfirmasikan penghapusan

Sebelum mengandalkan sebuah webhook di produksi, ujilah terlebih dahulu:

  1. Klik tindakan Test pada webhook Anda
  2. LabelGrid mengirimkan payload uji ke URL Anda
  3. Pastikan endpoint Anda menerima dan memprosesnya dengan benar

Pantau aktivitas webhook dan atasi masalah:

  1. Klik tindakan View Logs pada sebuah webhook
  2. Lihat riwayat seluruh pengiriman webhook

Setiap entri log menampilkan:

FieldDeskripsi
Event TypePeristiwa apa yang memicu pengiriman ini
Response StatusKode status HTTP dari server Anda
DurationBerapa lama permintaan tersebut berlangsung
AttemptNomor percobaan ulang
TimestampKapan pengiriman terjadi

Saat sebuah peristiwa terjadi, LabelGrid mengirim permintaan POST ke URL Anda dengan payload JSON:

{
"event": "delivery.completed",
"timestamp": "2026-05-05T10:00:00+00:00",
"webhook_id": "123",
"data": {
// Event-specific data
}
}

Field timestamp menggunakan format ISO 8601. webhook_id adalah ID webhook yang Anda konfigurasi (nilainya cocok dengan header X-Webhook-Id).


Struktur objek data bergantung pada jenis event. Semua tipe field di bawah ini adalah tipe JSON sebagaimana diserialisasikan dalam payload.

Dipicu satu kali per outlet saat pengiriman sebuah rilis mencapai status keberhasilan akhir.

{
"event": "delivery.completed",
"timestamp": "2026-05-18T10:00:00+00:00",
"webhook_id": "123",
"data": {
"distro_queue_id": 456,
"release_id": 789,
"release_cat": "ABC123",
"outlet_id": 12,
"outlet_name": "Spotify",
"status": "complete"
}
}
FieldTipeDeskripsi
distro_queue_idintegerID antrean internal untuk percobaan pengiriman ini
release_idintegerRilis yang dikirimkan
release_catstring | nullReferensi katalog rilis Anda
outlet_idintegerID outlet tujuan
outlet_namestring | nullNama outlet yang mudah dibaca (mis. "Spotify")
statusstringSelalu "complete" untuk peristiwa ini

Dipicu satu kali per outlet saat pengiriman sebuah rilis mencapai status kegagalan akhir. Payload-nya sama dengan delivery.completed ditambah field message.

{
"event": "delivery.failed",
"timestamp": "2026-05-18T10:00:00+00:00",
"webhook_id": "123",
"data": {
"distro_queue_id": 456,
"release_id": 789,
"release_cat": "ABC123",
"outlet_id": 12,
"outlet_name": "Spotify",
"status": "error",
"message": "Outlet rejected the delivery: missing ISRC."
}
}
FieldTipeDeskripsi
statusstringSalah satu dari error, fault, rejected, batch_exception
messagestring | nullAlasan kegagalan dari outlet atau pipeline distribusi

Dipicu satu kali per outlet saat permintaan takedown berhasil. Bentuknya sama dengan delivery.completed ditambah flag takedown: true.

{
"event": "takedown.completed",
"timestamp": "2026-05-18T10:00:00+00:00",
"webhook_id": "123",
"data": {
"distro_queue_id": 456,
"release_id": 789,
"release_cat": "ABC123",
"outlet_id": 12,
"outlet_name": "Spotify",
"status": "complete",
"takedown": true
}
}

Dipicu satu kali per rilis saat rilis beralih ke status pengiriman distributed. Hanya dipicu pada saat peralihan menjadi distributed, bukan pada penyimpanan berikutnya selama rilis sudah berstatus distributed.

{
"event": "release.distributed",
"timestamp": "2026-05-18T10:00:00+00:00",
"webhook_id": "123",
"data": {
"release_id": 789,
"release_cat": "ABC123",
"release_title": "Summer EP",
"delivery_status": "distributed"
}
}

Dipicu setiap kali sebuah rilis berpindah antar status peninjauan.

{
"event": "release.review.status_changed",
"timestamp": "2026-05-18T10:00:00+00:00",
"webhook_id": "123",
"data": {
"release_id": 789,
"release_cat": "ABC123",
"release_title": "Summer EP",
"previous_status": "to_review",
"new_status": "approved"
}
}
FieldTipeDeskripsi
previous_statusstringStatus sebelumnya. Salah satu dari draft, to_review, approved, rejected, require_changes, audit
new_statusstringStatus baru. Kumpulan nilai yang sama

Dipicu saat laporan pembayaran dibuat dan siap untuk dilihat.

{
"event": "payment.statement_ready",
"timestamp": "2026-05-18T10:00:00+00:00",
"webhook_id": "123",
"data": {
"payment_request_id": 1024,
"invoice_number": "INV-2026-001",
"period": "2026-04-30",
"amount": 1234.56,
"total_due_usd": 1234.56,
"currency": "USD"
}
}
FieldTipeDeskripsi
payment_request_idintegerID permintaan pembayaran internal
invoice_numberstringReferensi faktur untuk laporan tersebut
periodstring | nullTanggal akhir periode (tanggal ISO 8601, YYYY-MM-DD)
amountnumberJumlah laporan dalam currency
total_due_usdnumberTotal laporan yang dikonversi ke USD
currencystringKode mata uang ISO 4217 (default-nya USD)

Setiap pengiriman webhook ditandatangani sehingga Anda dapat memverifikasi bahwa pengiriman tersebut memang berasal dari LabelGrid. Selalu verifikasi signature sebelum memproses peristiwa.

Setiap permintaan POST webhook menyertakan header berikut:

HeaderDeskripsi
X-Webhook-SignatureHMAC-SHA256 dari body permintaan mentah, heksadesimal huruf kecil, tanpa awalan algoritma
X-Webhook-TimestampTimestamp ISO 8601 pengiriman (nilainya sama dengan properti timestamp di body)
X-Webhook-EventPengidentifikasi peristiwa (mis. delivery.completed)
X-Webhook-IdID webhook yang menerima pengiriman
User-AgentLabelGrid-Webhooks/1.0
Content-Typeapplication/json
  • Algoritma: HMAC-SHA256
  • Pengodean: Heksadesimal huruf kecil
  • Awalan: Tidak ada; nilainya hanya berupa hex digest, bukan sha256=...
  • Konten yang ditandatangani: Seluruh body permintaan JSON mentah (body itu sendiri menyertakan timestamp sebagai properti, sehingga timestamp ikut ditandatangani secara implisit)
  1. Baca body permintaan mentah sebelum parsing atau transformasi JSON apa pun. Menserialisasi ulang JSON yang sudah diparsing dapat menghasilkan byte yang berbeda dan merusak signature.
  2. Hitung HMAC-SHA256(raw_body, your_webhook_secret) lalu ambil hex digest huruf kecilnya.
  3. Bandingkan dengan X-Webhook-Signature menggunakan perbandingan constant-time.
  4. (Disarankan) Tolak permintaan jika X-Webhook-Timestamp lebih lama dari jendela toleransi replay Anda; kami menyarankan 5 menit.
$rawBody = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
$expected = hash_hmac('sha256', $rawBody, $webhookSecret);
if (! hash_equals($expected, $signature)) {
http_response_code(401);
exit('Invalid signature');
}
// Reject deliveries older than 5 minutes
if (abs(time() - strtotime($timestamp)) > 300) {
http_response_code(401);
exit('Stale delivery');
}
$payload = json_decode($rawBody, true);
// ... process the event
http_response_code(200);
const crypto = require('crypto');
// Express: capture raw body BEFORE any JSON middleware
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const rawBody = req.body; // Buffer
const signature = req.header('X-Webhook-Signature') || '';
const timestamp = req.header('X-Webhook-Timestamp') || '';
const expected = crypto
.createHmac('sha256', webhookSecret)
.update(rawBody)
.digest('hex');
const sigBuf = Buffer.from(signature, 'hex');
const expBuf = Buffer.from(expected, 'hex');
if (sigBuf.length !== expBuf.length || !crypto.timingSafeEqual(sigBuf, expBuf)) {
return res.status(401).send('Invalid signature');
}
if (Math.abs(Date.now() - new Date(timestamp).getTime()) > 5 * 60 * 1000) {
return res.status(401).send('Stale delivery');
}
const payload = JSON.parse(rawBody.toString('utf8'));
// ... process the event
res.sendStatus(200);
});
import hmac, hashlib
from datetime import datetime, timezone
raw_body = request.get_data() # Flask: bytes, before any JSON parsing
signature = request.headers.get('X-Webhook-Signature', '')
timestamp = request.headers.get('X-Webhook-Timestamp', '')
expected = hmac.new(
webhook_secret.encode('utf-8'),
raw_body,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, signature):
return ('Invalid signature', 401)
delivery_time = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
if abs((datetime.now(timezone.utc) - delivery_time).total_seconds()) > 300:
return ('Stale delivery', 401)
return ('', 200) # process the event, then ack
  • Menserialisasi ulang body sebelum hashing. Framework yang otomatis memparsing JSON (Express express.json(), body permintaan default Laravel) kehilangan byte aslinya. Tangkap body mentah terlebih dahulu.
  • Menggunakan perbandingan yang bukan constant-time (==, ===). Rentan terhadap serangan timing; selalu gunakan hash_equals (PHP), crypto.timingSafeEqual (Node), hmac.compare_digest (Python), atau padanannya di bahasa Anda.
  • Mengharapkan awalan sha256=. Nilai header hanyalah hex digest tanpa awalan.
  • Melewatkan pemeriksaan timestamp. Tanpa itu, signature yang bocor dapat diputar ulang tanpa batas.

BatasanNilai
Batas waktu permintaan10 detik
Ukuran payload maksimum64 KB
Webhook maksimum per pengguna10

Jika endpoint Anda tidak merespons dalam 10 detik, pengiriman dianggap gagal dan dicoba ulang.

Jika endpoint Anda mengembalikan status non-2xx atau melewati batas waktu, LabelGrid mencoba ulang dengan backoff eksponensial:

PercobaanJeda sebelum percobaan ulang
1 → 230 detik
2 → 31 menit
3 → 42 menit
4 → 54 menit
5 → 68 menit
6 → 716 menit
7 → 832 menit
8 → 964 menit
9 → 10128 menit

Setiap interval mencakup jitter 0–30 detik. Setelah 10 percobaan (total waktu berlalu sekitar 4,5 jam), pengiriman dicatat sebagai gagal permanen dan tidak dicoba ulang lagi.

Jika sebuah webhook mengakumulasi 100 pengiriman gagal secara kumulatif, webhook tersebut akan dinonaktifkan secara otomatis. Aktifkan kembali secara manual dalam daftar webhook setelah Anda memperbaiki endpoint Anda. Mengaktifkan kembali webhook yang dinonaktifkan akan mengatur ulang hitungan kegagalannya.

  • Kembalikan respons 2xx dengan cepat (dalam 10 detik)
  • Proses data secara asinkron setelah memberi konfirmasi
  • Verifikasi signature pada setiap permintaan (lihat Memverifikasi Signature Webhook)
  • Pantau hitungan kegagalan Anda dalam daftar webhook
  • Periksa log pengiriman saat menyelidiki peristiwa yang terlewat

  • Kirim pesan Slack saat rilis tayang
  • Kirim email ke tim Anda saat pengiriman gagal
  • Perbarui dasbor internal
  • Picu kampanye pemasaran saat rilis didistribusikan
  • Perbarui situs web Anda saat konten baru tersedia
  • Sinkronkan status ke alat manajemen proyek eksternal
  • Dapatkan peringatan seketika untuk kegagalan pengiriman
  • Pantau perkembangan distribusi secara waktu nyata
  • Pantau perubahan status peninjauan

  1. Periksa status - Apakah webhook berstatus Active?
  2. Verifikasi URL - Apakah endpoint dapat diakses dari internet?
  3. Periksa peristiwa - Apakah peristiwa yang tepat sudah dipilih?
  4. Tinjau log - Adakah kesalahan yang tercatat?
  1. Periksa endpoint Anda - Apakah mengembalikan 200 OK?
  2. Periksa waktu respons - Apakah merespons dalam batas waktu?
  3. Tinjau pesan kesalahan - Apa yang gagal?
  4. Uji secara manual - Kirim webhook uji

Jika secret webhook Anda bocor:

  1. Klik Regenerate Secret di pengaturan webhook
  2. Perbarui aplikasi Anda dengan secret baru
  3. Secret lama langsung berhenti berfungsi

Jika Anda memiliki pertanyaan tentang webhook, hubungi tim dukungan kami.

Belum menggunakan LabelGrid?

Semua yang baru saja Anda baca tersedia di platform kami.

Lihat kemampuan LabelGrid →