paypal = new PaypalService(); $this->customerService = $customerService; } protected function isValidWebhook() { // get request headers $headers = apache_request_headers(); Log::info($headers); // get http payload $body = file_get_contents('php://input'); $webhook_id = '6V2767039S933004S'; //live $data = $headers['PAYPAL-TRANSMISSION-ID'] . '|' . $headers['PAYPAL-TRANSMISSION-TIME'] . '|' . $webhook_id . '|' . crc32($body); // load certificate and extract public key $pubKey = openssl_pkey_get_public(file_get_contents($headers['PAYPAL-CERT-URL'])); $key = openssl_pkey_get_details($pubKey)['key']; // verify data against provided signature $result = openssl_verify( $data, base64_decode($headers['PAYPAL-TRANSMISSION-SIG']), $key, 'sha256WithRSAEncryption' ); if ($result == 1) { // webhook notification is verified Log::info('webhook verified'); return true; } elseif ($result == 0) { // webhook notification is NOT verified Log::info('webhook not verified'); return false; } else { // there was an error verifying this Log::info('webhook verification error'); return false; } } public function webhook(Request $request) { // Verify that the webhook is authentic if (!$this->isValidWebhook()) { Log::error('Received invalid webhook'); return response('Invalid webhook', 400); exit(); } // Get the webhook data from the request $webhookData = $request->all(); $event_type = $webhookData["event_type"]; Log::info($webhookData); if($event_type == 'CHECKOUT.ORDER.APPROVED'){ try { $total = 0; $user_id = null; $coupon_id = null; foreach ($webhookData['resource']['purchase_units'] as $key => $purchase_unit) { $total += (float) $purchase_unit['amount']['value']; $custom_data = json_decode($purchase_unit['custom_id']); $user_id = $custom_data->user_id; if(isset($custom_data->coupon_id)){ $coupon_id = $custom_data->coupon_id; } } $alacarte_order = AlacarteOrder::create([ 'order_number' => rand(11, 99).date('ymdhis'), 'user_id' => $user_id, 'paypal_order_id' => $webhookData['resource']['id'], 'total' => $total * 100, 'status' => 'waiting for payment' ]); if($coupon_id != null){ $coupon = SubscriptionCoupon::find((int)$coupon_id); if($coupon){ $coupon_redemption = new SubscriptionCouponRedemption; $coupon_redemption->subscription_coupon_id = $coupon->id; $coupon_redemption->customer_id = $alacarte_order->user_id; $coupon_redemption->alacarte_order_id = $alacarte_order->id; $coupon_redemption->save(); } } $user_credits = UserCredit::firstOrCreate(['user_id' => $user_id]); $captureResponse = $this->paypal->capturePayment($webhookData['resource']['id']); if($captureResponse->status == 'COMPLETED'){ $alacarte_order->status = 'paid'; $alacarte_order->save(); Log::info($captureResponse->purchase_units); foreach ($captureResponse->purchase_units as $key => $purchase_unit) { $alacarte = Alacarte::with('category')->where('id',(int)$purchase_unit->reference_id)->first(); if($alacarte){ $capture_data = $purchase_unit->payments->captures[0]; $custom_data = json_decode($capture_data->custom_id); $quantity = $custom_data->quantity; $discount = $custom_data->discount; $total_price = $capture_data->amount->value; $alacarte_order->items()->create([ 'alacarte_id' => $alacarte->id, 'price' => ($total_price / $quantity) + $discount, 'quantity' => $quantity, 'discount' => ($discount * $quantity) * 100, 'total' => $total_price * 100, ]); if($capture_data->status == 'COMPLETED'){ Log::info('Updating user credits'); $before_credits = $this->customerService->credits($user_credits->user_id); $user_credits->alacarte_credits = $user_credits->alacarte_credits + ($alacarte->credits * $quantity); $user_credits->save(); $after_credits = $this->customerService->credits($user_credits->user_id); $user_credits_history = new UserCreditHistory; $user_credits_history->user_id = $user_credits->user_id; $user_credits_history->subscription_credits_from = $before_credits['total_available_credits']['subscription']; $user_credits_history->subscription_credits_to = $after_credits['total_available_credits']['subscription']; $user_credits_history->alacarte_credits_from = $before_credits['total_available_credits']['alacarte'];; $user_credits_history->alacarte_credits_to = $after_credits['total_available_credits']['alacarte']; $user_credits_history->details = 'Added '.$quantity.'X '.$alacarte->name; $user_credits_history->save(); } } } } else { Log::info('Capture Payment Failed'); } } catch(\Exception $e) { Log::info($e->getMessage()); http_response_code(400); exit(); } } else { Log::info($webhookData); } } }