Webhooks — PHP SDK
Verify and handle webhooks
// Get the raw POST body and signature header
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIMIZ_SIGNATURE'];
$webhookSecret = getenv('SIMIZ_WEBHOOK_SECRET');
try {
$event = $simiz->webhooks->constructEvent(
$payload,
$signature,
$webhookSecret
);
switch ($event->type) {
case 'payment.succeeded':
$payment = $event->data;
// Update order status
break;
case 'payment.failed':
// Notify customer
break;
case 'refund.succeeded':
// Process refund
break;
}
http_response_code(200);
echo json_encode(['received' => true]);
} catch (\Simiz\Exception\SignatureVerificationException $e) {
http_response_code(401);
echo 'Invalid signature';
}
Laravel example
// routes/api.php
Route::post('/webhooks/simiz', [WebhookController::class, 'handle']);
// app/Http/Controllers/WebhookController.php
class WebhookController extends Controller
{
public function handle(Request $request)
{
$payload = $request->getContent();
$signature = $request->header('X-Simiz-Signature');
try {
$event = app(SimizClient::class)->webhooks->constructEvent(
$payload,
$signature,
config('services.simiz.webhook_secret')
);
match ($event->type) {
'payment.succeeded' => $this->handlePaymentSuccess($event->data),
'payment.failed' => $this->handlePaymentFailure($event->data),
default => null,
};
return response()->json(['received' => true]);
} catch (SignatureVerificationException $e) {
return response('Invalid signature', 401);
}
}
}
Manual verification
Signature format:
X-Simiz-Signature: t=<timestamp>,v1=<hmac_sha256_hex>The timestamp protects against replay attacks. Signatures older than 5 minutes are rejected.function verifyWebhook(string $payload, string $signatureHeader, string $secret, int $toleranceSeconds = 300): bool
{
// Parse signature header: t=<timestamp>,v1=<hash>
$parts = explode(',', $signatureHeader);
$timestamp = null;
$hash = null;
foreach ($parts as $part) {
if (str_starts_with($part, 't=')) {
$timestamp = (int) substr($part, 2);
} elseif (str_starts_with($part, 'v1=')) {
$hash = substr($part, 3);
}
}
if ($timestamp === null || $hash === null) {
return false;
}
// Check timestamp is within tolerance (default: 5 minutes)
$now = time();
if (abs($now - $timestamp) > $toleranceSeconds) {
return false;
}
// Calculate expected signature
$signaturePayload = $timestamp . '.' . $payload;
$expectedSignature = hash_hmac('sha256', $signaturePayload, $secret);
// Timing-safe comparison
return hash_equals($hash, $expectedSignature);
}

