client = new PayPalClient; } public function deposit($amount, $currency, $trxId) { $paymentPayload = [ 'intent' => 'sale', 'payer' => [ 'payment_method' => 'paypal', ], 'transactions' => [ [ 'amount' => [ 'total' => number_format($amount, 2), 'currency' => $currency, ], 'description' => $trxId, ], ], 'redirect_urls' => [ 'return_url' => route('ipn.handle', ['gateway' => 'paypal']), 'cancel_url' => route('status.cancel', ['trx_id' => $trxId]), ], ]; $payment = $this->client->createPayment($paymentPayload); Session::put('cancel_tnx', $trxId); foreach ($payment->links as $link) { if ($link->rel === 'approval_url') { return $link->href; } } return true; } public function withdraw($amount, $currency, $trxId, $withdrawCredential) { // Build PayPal Payouts request payload $payoutData = [ 'sender_batch_header' => [ 'sender_batch_id' => uniqid(), // Unique ID for tracking 'email_subject' => 'You have a payout!', 'email_message' => 'You have received a payout!', ], 'items' => [ [ 'recipient_type' => 'EMAIL', 'receiver' => $withdrawCredential, 'note' => 'Withdrawal Payout', 'sender_item_id' => $trxId, 'amount' => [ 'value' => number_format($amount, 2, '.', ''), 'currency' => $currency, ], ], ], ]; $this->client->payoutPayment($payoutData); } public function handleIPN(Request $request) { // If 'event_type' is present, this is a PayPal webhook event. if ($request->has('event_type')) { return $this->handleWebhookEvent($request); } // Otherwise, it's the user returning from PayPal (execute the payment). return $this->handleExecutePayment($request); } protected function handleWebhookEvent(Request $request): JsonResponse { // Extract the event type and log the full payload for debugging purposes $eventType = $request->input('event_type'); Log::info("Received PayPal Webhook: {$eventType}", $request->all()); // Extract the sender item ID (your transaction ID used in payout creation) $payoutItemId = $request->input('resource.payout_item.sender_item_id', null); // Handle different event types switch ($eventType) { case 'PAYMENT.PAYOUTS-ITEM.SUCCESS': // Mark the transaction as successful Transaction::completeTransaction($payoutItemId); break; case 'PAYMENT.PAYOUTSBATCH.PROCESSING': // Ignore processing events (no action needed) Log::info('Payout batch is still processing. No action taken.'); break; default: // Handle all other scenarios with a unified failure action if ($payoutItemId) { Transaction::cancelTransaction( $payoutItemId, __('Your withdrawal request was unsuccessful. The amount has been refunded. Please contact the administrator for assistance.'), true ); } Log::warning("Unhandled PayPal Webhook event type: {$eventType}"); break; } // Return a success response to PayPal to acknowledge receipt of the webhook return response()->json(['status' => 'success']); } /** * Handle the payment execution flow when the user returns from PayPal. */ protected function handleExecutePayment(Request $request): RedirectResponse { // Validate that required parameters exist; you can add further validation as needed. $request->validate([ 'paymentId' => 'required|string', 'PayerID' => 'required|string', ]); // Execute the payment via your PayPal client $response = $this->client->executePayment( $request->input('paymentId'), $request->input('PayerID') ); // Check the response state if (isset($response->state) && $response->state === 'approved') { // Fetch your transaction ID (assuming you stored it in the 'description') $trxId = $response->transactions[0]->description ?? null; // Mark the transaction as complete in your system Transaction::completeTransaction($trxId); // Notify and redirect notifyEvs('success', __('Payment Successful')); return redirect()->route('status.success', ['trx_id' => $trxId]); } // If not approved, handle failure accordingly notifyEvs('warning', __('Something went wrong. Please try again.')); return redirect()->back(); } } ------------------------------------------ credentials = PaymentGateway::getCredentials('paypal'); $this->client = new Client([ 'base_uri' => $this->credentials['mode'] === 'sandbox' ? 'https://api.sandbox.paypal.com/' : 'https://api.paypal.com/', ]); } // Fetch Access Token from PayPal public function createPayment(array $payload) { return $this->makeRequest('POST', 'v1/payments/payment', $payload); } // Function to execute an approved payment public function executePayment(string $paymentId, string $payerId) { return $this->makeRequest('POST', "v1/payments/payment/{$paymentId}/execute", [ 'payer_id' => $payerId, ]); } public function payoutPayment($payoutData): mixed { $response = $this->makeRequest( 'POST', 'v1/payments/payouts', $payoutData ); Log::info('PayPal Payout Response:', (array) $response); return $response; } // Centralize API requests protected function makeRequest(string $method, string $uri, array $data = []) { $response = $this->client->request($method, $uri, [ 'headers' => [ 'Authorization' => 'Bearer '.$this->getAccessToken(), 'Content-Type' => 'application/json', ], 'json' => $data, ]); return json_decode($response->getBody()->getContents()); } // Function to create a payment request protected function getAccessToken(): string { if (! $this->accessToken) { $response = $this->client->post('v1/oauth2/token', [ 'auth' => [$this->credentials['client_id'], $this->credentials['client_secret']], 'form_params' => [ 'grant_type' => 'client_credentials', ], ]); $this->accessToken = json_decode($response->getBody()->getContents())->access_token; } return $this->accessToken; } } ---------------------------------------- نیازمندي سایت شما براي اتصال به سیستم پرداخت آیدی پال فقط فعال بودن تابع CURL بوده که در اکثر سرور ها این تابع فعال می باشد. براي مطمئن شدن از فعال بودن این تابع با مدیر سرور خود تماس حاصل فرمایید. داده های ارسالی : بطور کلی سایت مبدا براي انجام تراکنش باید موارد زیر را به آدرس https://idpal.ir/webservice/paymentRequest.php و به شیوه POST ارسال نماید مواردی که باید بصورت POST بمنظور ایجاد تراکنش به وب سرویس آیدی پال ارسال شود : پارامترهای ارسالی مثال توضیح MerchantID xxxxxxxxxxxxxxxx مرچنت آیدی در بخش " درگاهای من " در پنل کاربری شما در قابل مشاهده میباشد Amount 100 مبلغی که در تراکنش ارسال و قابل پرداخت میباشد, واحد مبلغ ارسالی تومان و حداقل مبلغ قابل پرداخت 100 تومان میباشد Description تراکنش شماره 15 متني كه توسط پذيرنده تعيين ميشود كه نشان دهنده خلاصه محصول يا سرويسي است كه پذيرنده قصد فروش آن را دارد CallbackURL http://example.com/verify.php آدرس بازگشتی که بعد از انجام عملیات تراکنش، آیدی پال اطلاعات را به آنجا ارسال خواهد کرد InvoiceNumber 15 شماره تراکنش, این شماره پس از پرداخت برای سایت فروشنده ارسال خواهد شد CardNumber 6037991100000000 شماره کارت پرداخت کننده ( این مورد میتواند خالی باشد ) لیست داده هاي برگشتی آیدی پال زمان ارسال داده : پارامترهای برگشتی مثال توضیح Status 100 وضعيت درخواست كه در صورت موفقيت آميز بودن برابر 100 در غير اين صورت عددي منفي ميباشد Authority 1000010 شناسه مرجع درخواست، درصورت موفق بودن داراي یک عدد صحیح می باشد در صورت صحت داده ها آیدی پال یک داده از نوع صحیح و بزرگتر از 0 ( که Authority نام دارد ) و یک داده با نام Status برابر 100 بر می گرداند و سایت پذیرنده پس از دریافت این داده ها، مشتري را به سایت آیدی پال هدایت می نماید, توجه داشته باشید که در داده های برگشتی در صورتی که مقدار Status برابر با 100 نباشد, برابر با یک عدد منفی خواهد بود که شرح خطاهای هر عدد منفی را در تب کدهای برگشتی / خطاها / توضیحات مشاهده کنید توجه داشته باشید مقدار بازگشتی Authority و Status بصورت JSON میباشد بطور مثال در صورتی که مقدار Authority بازگشتی برابر با 1000010 باشد بمنظور اتصال به درگاه بانکی و انجام عملیات پرداخت کاربر باید به آدرس زیر هدایت شود : https://idpal.ir/startPay/1000010 نمونه کد PHP ایجاد شناسه ی پرداخت ( Authority ) و ارجاع کاربر به درگاه پرداخت : 'application/json')); curl_setopt($curl, CURLOPT_POSTFIELDS, "MerchantID={$MerchantID}&Amount={$Amount}&Description={$Description}&InvoiceNumber={$InvoiceNumber}&CardNumber={$CardNumber}&CallbackURL=". urlencode($CallbackURL)); curl_setopt($curl, CURLOPT_TIMEOUT, 30); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $curl_exec = curl_exec($curl); curl_close($curl); $result = json_decode($curl_exec); if (isset($result->Status) && $result->Status == 100) { header("Location: https://idpal.ir/startPay/{$result->Authority}"); } else { echo (isset($result->Status) && $result->Status != "") ? $result->Status : "-13"; } ?> داده هاي دریافتی : بعد از انجام پرداخت، آیدی پال مشتري را به آدرسی که در CallbackURL ارسال شده است، همراه با دو متغیر از نوع POST هدایت میکند. سایت پذیرنده، براي اطمینان یک بار دیگر و بر اساس این دو متغیر از آیدی پال پرس و جو کرده، و از صحت تراکنش انجام شده اطمینان حاصل می نماید. لیست داده هاي برگشتی آیدی پال زمان دریافت داده : پارامترهای برگشتی مثال توضیح Status 100 وضعيت درخواست كه در صورت موفقيت آميز بودن برابر 100 در غير اين صورت عددي منفي ميباشد RefID 1000010 در صورتي كه پرداخت موفق باشد؛ شماره تراكنش پرداخت انجام شده را بر ميگرداند. Amount 1000 مبلغ پرداخت شده ( مبلغ به تومان می باشد ) MaskCardNumber 123456****894564 شماره کارت Mask شده خریدار ( شماره کارتی که پرداخت وجه توسط آن انجام شده است ) چنانچه authority یک عدد صحیح بزرگتر از 0 بود سایت پذیرنده باید براي صحت تراکنش داده هاي Authority ، Amount ، MerchantID را به آدرس زیر به شیوه POST ارسال نماید : https://idpal.ir/webservice/paymentVerify.php در صورتی که مقدار بازگشتی Status برابر با 100 باشد تراکنش بدرستی انجام شده است در غیر اینصورت مقدار بازگشتی برابر با یک عدد منفی خواهد بود که شرح خطاهای مرتبط با هر عدد منفی بازگشتی را میتوانید در تب کدهای برگشتی / خطاها / توضیحات مشاهده کنید. توجه داشته باشید مقدار بازگشتی Authority و Status و Amount بصورت JSON میباشد نمونه کد PHP تصدیق اصالت پس از پرداخت ( عملیات Verify کردن تراکنش ) : 'application/json')); curl_setopt($curl, CURLOPT_POSTFIELDS, "MerchantID={$MerchantID}&Amount={$Amount}&Authority={$Authority}"); curl_setopt($curl, CURLOPT_TIMEOUT, 30); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $curl_exec = curl_exec($curl); curl_close($curl); $result = json_decode($curl_exec); if (isset($result->Status) && $result->Status == 100) { echo 'Transation success. Amount : '. $result->Amount .' Toman AND RefID : '. $result->RefID; } else { echo (isset($result->Status) && $result->Status != "") ? $result->Status : "-13"; } } else { echo 'Transaction Canceled By User'; } ?>