value('value'); abort_if($secret === '', 503, 'Webhook تلفن پیکربندی نشده است.'); $signature = (string) $request->header('X-VoIP-Signature'); $expected = hash_hmac('sha256', $request->getContent(), $secret); abort_unless($signature !== '' && hash_equals($expected, $signature), 401, 'امضای Webhook معتبر نیست.'); $validated = $request->validate([ 'provider_call_id' => 'required|string|max:255', 'status' => 'required|in:initiated,ringing,answered,completed,failed,busy,no_answer,cancelled', 'duration_seconds' => 'nullable|integer|min:0|max:86400', 'recording_url' => 'nullable|url|max:2048', 'result' => 'nullable|string|max:50', 'started_at' => 'nullable|date', 'ended_at' => 'nullable|date', ]); $call = Call::where('provider_call_id', $validated['provider_call_id'])->firstOrFail(); $terminal = in_array($validated['status'], ['completed', 'failed', 'busy', 'no_answer', 'cancelled'], true); $call->update([ 'provider_status' => $validated['status'], 'duration' => $validated['duration_seconds'] ?? $call->duration, 'recording_url' => $validated['recording_url'] ?? $call->recording_url, 'result' => $validated['result'] ?? $call->result, 'started_at' => $validated['started_at'] ?? $call->started_at, 'ended_at' => $validated['ended_at'] ?? ($terminal ? now() : $call->ended_at), 'provider_payload' => $request->all(), ]); CallLog::where('call_id', $call->id)->update([ 'recording_url' => $call->recording_url, 'result' => $call->result, ]); ActivityLogger::log('voip_webhook_received', "VoIP status {$validated['status']} received for call {$call->id}", $call, null, ['provider_call_id' => $call->provider_call_id]); return response()->json(['ok' => true, 'call_id' => $call->id]); } }