Overview
PayPal is one of the world’s most popular payment platforms, enabling customers to pay using their PayPal balance, credit cards, or debit cards. Ecom uses the PayPal Checkout SDK for seamless integration.
Prerequisites
PayPal Business account (Sign up here )
PayPal API credentials (Client ID and Secret)
SSL certificate for production
Configuration
Step 1: Get PayPal API Credentials
Login to PayPal Developer
Create an App
Navigate to Apps & Credentials and click Create App
Copy Credentials
Copy your Client ID and Secret from the app details
Choose Environment
Toggle between Sandbox (testing) and Live (production)
Add PayPal credentials to your .env file:
# PayPal Configuration
PAYPAL_CLIENT_ID = AZD...
PAYPAL_CLIENT_SECRET = EL...
PAYPAL_SANDBOX = 1 # Set to 0 for production
Set PAYPAL_SANDBOX=1 for testing with sandbox accounts, and PAYPAL_SANDBOX=0 when going live.
Step 3: Enable PayPal in Admin Panel
Access Admin Dashboard
Login to your admin panel
Navigate to Payment Methods
Go to Setup & Configurations → Payment Methods
Activate PayPal
Enable PayPal and configure sandbox mode in business settings
Implementation Details
Controller Location
app/Http/Controllers/Payment/PaypalController.php
Payment Flow
Initialize PayPal Client
System creates PayPal HTTP client with environment configuration app/Http/Controllers/Payment/PaypalController.php
public function pay ()
{
// Creating an environment
$clientId = env ( 'PAYPAL_CLIENT_ID' );
$clientSecret = env ( 'PAYPAL_CLIENT_SECRET' );
if ( get_setting ( 'paypal_sandbox' ) == 1 ) {
$environment = new SandboxEnvironment ( $clientId , $clientSecret );
} else {
$environment = new ProductionEnvironment ( $clientId , $clientSecret );
}
$client = new PayPalHttpClient ( $environment );
}
Create PayPal Order
Prepare order details and create PayPal order app/Http/Controllers/Payment/PaypalController.php
if ( Session :: has ( 'payment_type' )) {
if ( Session :: get ( 'payment_type' ) == 'cart_payment' ) {
$combined_order = CombinedOrder :: findOrFail ( Session :: get ( 'combined_order_id' ));
$amount = $combined_order -> grand_total ;
}
}
$request = new OrdersCreateRequest ();
$request -> prefer ( 'return=representation' );
$request -> body = [
"intent" => "CAPTURE" ,
"purchase_units" => [[
"reference_id" => rand ( 000000 , 999999 ),
"amount" => [
"value" => number_format ( $amount , 2 , '.' , '' ),
"currency_code" => \App\Models\ Currency :: findOrFail ( get_setting ( 'system_default_currency' )) -> code
]
]],
"application_context" => [
"cancel_url" => url ( 'paypal/payment/cancel' ),
"return_url" => url ( 'paypal/payment/done' )
]
];
Redirect to PayPal
Customer is redirected to PayPal for payment app/Http/Controllers/Payment/PaypalController.php
try {
$response = $client -> execute ( $request );
return Redirect :: to ( $response -> result -> links [ 1 ] -> href );
} catch ( \ Exception $ex ) {
flash ( translate ( 'Something was wrong' )) -> error ();
return redirect () -> route ( 'home' );
}
Capture Payment
After customer approves payment, capture the order app/Http/Controllers/Payment/PaypalController.php
public function getDone ( Request $request )
{
$clientId = env ( 'PAYPAL_CLIENT_ID' );
$clientSecret = env ( 'PAYPAL_CLIENT_SECRET' );
if ( get_setting ( 'paypal_sandbox' ) == 1 ) {
$environment = new SandboxEnvironment ( $clientId , $clientSecret );
} else {
$environment = new ProductionEnvironment ( $clientId , $clientSecret );
}
$client = new PayPalHttpClient ( $environment );
$ordersCaptureRequest = new OrdersCaptureRequest ( $request -> token );
$ordersCaptureRequest -> prefer ( 'return=representation' );
try {
$response = $client -> execute ( $ordersCaptureRequest );
if ( $request -> session () -> has ( 'payment_type' )) {
if ( $request -> session () -> get ( 'payment_type' ) == 'cart_payment' ) {
return ( new CheckoutController ) -> checkout_done ( $request -> session () -> get ( 'combined_order_id' ), json_encode ( $response ));
}
}
} catch ( \ Exception $ex ) {
// Handle error
}
}
PayPal requires amounts in decimal format with 2 decimal places: "value" => number_format ( $amount , 2 , '.' , '' ) // Correct: "100.00"
"value" => $amount // May cause errors
Currency Support
PayPal supports 25+ currencies. The system uses your default currency:
"currency_code" => \App\Models\ Currency :: findOrFail ( get_setting ( 'system_default_currency' )) -> code
Supported currencies include:
USD, EUR, GBP, CAD, AUD
JPY, CNY, INR, MXN, BRL
And many more
Routes Configuration
Required routes in routes/web.php:
// PayPal Payment Routes
Route :: get ( 'paypal/payment' , [ PaypalController :: class , 'pay' ]) -> name ( 'paypal.pay' );
Route :: get ( 'paypal/payment/done' , [ PaypalController :: class , 'getDone' ]) -> name ( 'paypal.done' );
Route :: get ( 'paypal/payment/cancel' , [ PaypalController :: class , 'getCancel' ]) -> name ( 'paypal.cancel' );
Dependencies
PayPal Checkout SDK is included via Composer:
"require" : {
"paypal/paypal-checkout-sdk" : "dev-master"
}
If not installed, run:
composer require paypal/paypal-checkout-sdk
Testing with Sandbox
Sandbox Configuration
Enable sandbox mode in .env:
The system automatically uses sandbox environment:
if ( get_setting ( 'paypal_sandbox' ) == 1 ) {
$environment = new SandboxEnvironment ( $clientId , $clientSecret );
} else {
$environment = new ProductionEnvironment ( $clientId , $clientSecret );
}
Create Sandbox Accounts
Access Sandbox Accounts
Go to PayPal Developer Dashboard → Sandbox → Accounts
Create Test Buyer
Create a personal (buyer) sandbox account
Create Test Seller
Create a business (seller) sandbox account (optional)
Get Credentials
View account credentials for testing
Test Sandbox Payments
Use sandbox account credentials to test:
Add items to cart on your test site
Select PayPal at checkout
Login with sandbox buyer account
Complete payment
Verify order completion
Payment Cancellation
When customers cancel payment:
app/Http/Controllers/Payment/PaypalController.php
public function getCancel ( Request $request )
{
$request -> session () -> forget ( 'order_id' );
$request -> session () -> forget ( 'payment_data' );
flash ( translate ( 'Payment cancelled' )) -> success ();
return redirect () -> route ( 'home' );
}
Supported Payment Types
PayPal integration supports all payment types:
Cart Payment
if ( Session :: get ( 'payment_type' ) == 'cart_payment' ) {
$combined_order = CombinedOrder :: findOrFail ( Session :: get ( 'combined_order_id' ));
$amount = $combined_order -> grand_total ;
}
Wallet Payment
elseif ( Session :: get ( 'payment_type' ) == 'wallet_payment' ) {
$amount = Session :: get ( 'payment_data' )[ 'amount' ];
}
Package Payments
elseif ( Session :: get ( 'payment_type' ) == 'customer_package_payment' ) {
$customer_package = CustomerPackage :: findOrFail ( Session :: get ( 'payment_data' )[ 'customer_package_id' ]);
$amount = $customer_package -> amount ;
}
Error Handling
The controller handles errors gracefully:
try {
$response = $client -> execute ( $request );
return Redirect :: to ( $response -> result -> links [ 1 ] -> href );
} catch ( \ Exception $ex ) {
flash ( translate ( 'Something was wrong' )) -> error ();
return redirect () -> route ( 'home' );
}
Troubleshooting
Cause : Invalid Client ID or SecretSolution :
Verify credentials in .env match PayPal Developer Dashboard
Ensure no extra spaces in credentials
Check you’re using correct environment (Sandbox vs Live)
Cause : Selected currency not supported by PayPalSolution :
Cause : Incorrect amount formattingSolution :// Use number_format for proper formatting
"value" => number_format ( $amount , 2 , '.' , '' )
Cause : Incorrect callback URLsSolution :
Ensure URLs use HTTPS in production
Verify routes are properly registered
Check .htaccess or nginx configuration
Going Live
Complete PayPal Business Account
Verify your business account with PayPal
Get Live API Credentials
Switch to Live in PayPal Developer Dashboard and get live credentials
Update Environment Variables
PAYPAL_CLIENT_ID =< your-live-client-id >
PAYPAL_CLIENT_SECRET =< your-live-secret >
PAYPAL_SANDBOX = 0
Update Business Settings
Disable sandbox mode in admin panel business settings
Test Live Payment
Make a small test transaction with real PayPal account
Webhooks (Advanced)
For real-time payment notifications:
Create Webhook in PayPal
Go to PayPal Developer Dashboard → Webhooks
Set Webhook URL
https://yourdomain.com/paypal/webhook
Select Events
Subscribe to:
PAYMENT.CAPTURE.COMPLETED
PAYMENT.CAPTURE.DENIED
CHECKOUT.ORDER.APPROVED
Security Best Practices
Protect Your API Credentials
Never commit .env file to version control
Use different credentials for sandbox and production
Implement webhook signature verification
Enable HTTPS for all payment pages
Regularly rotate API credentials
Payment Overview Learn about payment architecture
Stripe Integration Configure Stripe as alternative