search

No results found

API Reference chevron_right Webhook chevron_right Security
verified_user SECURITY

Signature Verification

Selalu verifikasi signature untuk memastikan callback benar-benar dari kami dan data tidak dimanipulasi.

security Mengapa Harus Verifikasi?

warning

Tanpa Verifikasi

Siapa saja bisa mengirim request palsu ke endpoint Anda dan memanipulasi data order.

verified_user

Dengan Verifikasi

Hanya callback yang memiliki signature valid (dari kami) yang akan diproses.

functions Cara Kerja Signature

Signature dibuat menggunakan algoritma SHA256 dengan format:

signature = SHA256(ref_id + ":" + invoice + ":" + status + ":" + webhook_secret)

Nilai status untuk signature bersifat event-dependent: payload.data.status untuk order.paid/order.completed/order.canceled, item.sent untuk order.item.sent, dan test untuk webhook.test.

Komponen Sumber
ref_id Dari payload.data.ref_id
invoice Dari payload.data.invoice
status Event-dependent (lihat catatan di atas)
webhook_secret Secret key Anda (dari generate secret)

checklist Langkah Verifikasi

1

Terima Callback

Parse JSON payload dari request body

2

Ambil Signature dari Header

Baca header X-Signature

3

Buat Expected Signature

Hitung signature menggunakan data dari payload + secret key Anda

4

Bandingkan dengan Timing-Safe

Gunakan hash_equals() untuk mencegah timing attack

5

Proses atau Tolak

Jika signature valid, proses data. Jika tidak, return 401.

lightbulb Tips Keamanan

info

Gunakan hash_equals()

Jangan gunakan == atau === untuk membandingkan signature. Gunakan hash_equals() untuk mencegah timing attack.

warning

Jaga Secret Key

Jangan pernah expose secret key di frontend, log, atau repository publik. Simpan di environment variable.

verified

HTTPS Only

Selalu gunakan HTTPS untuk callback URL. HTTP tidak aman dan data bisa disadap.

replay

Idempotency

Cek apakah order sudah pernah diproses sebelum melakukan update. Callback bisa dikirim lebih dari sekali.

PHP Implementation

<?php

// 1. Terima payload
$payload = json_decode(
    file_get_contents('php://input'),
    true
);

// 2. Ambil signature dari header
$receivedSignature = 
    $_SERVER['HTTP_X_SIGNATURE'] ?? '';

// 3. Buat expected signature
$webhookSecret = env('WEBHOOK_SECRET');
$event = $payload['event'] ?? '';

// status untuk signature tergantung event
$statusForSignature = match ($event) {
    'order.item.sent' => 'item.sent',
    'webhook.test' => 'test',
    default => $payload['data']['status'] ?? '',
};

$expectedSignature = hash('sha256', 
    sprintf(
        '%s:%s:%s:%s',
        $payload['data']['ref_id'] ?? '',
        $payload['data']['invoice'] ?? '',
        $statusForSignature,
        $webhookSecret
    )
);

// 4. Verifikasi (timing-safe)
if (!hash_equals(
    $expectedSignature, 
    $receivedSignature
)) {
    http_response_code(401);
    echo json_encode([
        'error' => 'Invalid signature'
    ]);
    exit;
}

// 5. Signature valid! Proses data
$data = $payload['data'];

switch ($event) {
    case 'order.completed':
        // Update status order
        // Kirim notifikasi customer
        break;
    
    case 'order.canceled':
        // Handle canceled
        break;

    case 'order.item.sent':
        // Handle delivery item manual secara real-time
        break;
}

http_response_code(200);
echo json_encode(['status' => 'ok']);
chat_bubble Feedback