Accept payments with PayPal on your Larapen Shop. This add-on integrates the PayPal REST API to create orders, capture payments, handle webhooks, and process refunds: all through the standard Larapen payment gateway interface.
PayPal Checkout
Redirect customers to PayPal’s hosted checkout. No credit card form needed on your site.
Sandbox & Live
Switch between sandbox (testing) and live (production) modes from the admin panel with a single toggle.
Webhook Support
Receive real-time payment notifications via PayPal webhooks for capture, denial, and refund events.
Refund Processing
Issue full or partial refunds directly through the gateway. Refund transactions are tracked automatically.
Encrypted Credentials
API keys and secrets are encrypted before storage using Laravel’s Crypt facade.
Polymorphic Payables
Works with any model implementing the Payable contract: not limited to shop orders.
Use Cases
Online Store with PayPal Checkout
You run an e-commerce store using the Larapen Shop add-on and want to offer PayPal as a payment option alongside other gateways (e.g. Stripe).
- Install and activate the PayPal add-on.
- Enter your PayPal REST API credentials in the admin panel.
- Customers see PayPal as a payment method during checkout.
- On selection, they are redirected to PayPal to complete payment, then returned to your site.
Digital Product Sales
You sell digital downloads (e-books, software licenses, templates) and want secure, instant payment confirmation.
- PayPal webhooks confirm payment in real time, even if the customer closes the browser before returning.
- The shop marks the order as paid and unlocks digital download links automatically.
Multi-Currency Store
You sell to international customers in multiple currencies.
- Configure the default PayPal currency in admin settings (USD, EUR, GBP, etc.).
- Each order sends the correct currency code to PayPal based on the shop configuration.
Requirements
- Larapen CMS v1.0.0 or later
- PHP 8.3+
- MySQL 8.0+
- The Shop add-on (required dependency)
- A PayPal Business account with REST API credentials
- The
srmklive/paypalComposer package (PayPal SDK)
Installation
Step 1: Upload the Add-on
In the admin panel, go to Admin → Extensions → Add-ons and click the Upload Add-on button. Select the add-on’s ZIP file: the system extracts it automatically and the add-on appears in the installed add-ons list.
Step 2: Activate the Add-on
Find PayPal Payment Gateway in the list and click Activate. Its migrations, seeders (if any) and permissions are set up automatically.
Step 3: Configure
Navigate to Admin → PayPal → Settings and enter your PayPal API credentials. See also Getting PayPal Credentials. See Configuration.
Purchase Code (License Key)
PayPal Payment Gateway is sold as a separate product, so it has its own purchase code (license key), distinct from the purchase code of the main application and from the one of every other add-on. You are asked for it when you activate PayPal Payment Gateway in Admin panel → Add-ons.
Our products are sold on three platforms. The way you receive a purchase code depends on where you bought the product.
| Platform / Marketplace | How you get the purchase code | Where to find it again |
|---|---|---|
| bedigit.com Store In-site purchase (Shop) |
Generated automatically when the order is paid, then sent by email, either in its own license email, or inside the order confirmation email. | My Account → My Licenses on bedigit.com |
| Gumroad | Created as soon as Gumroad notifies us of the sale, then sent in a separate email, in addition to the Gumroad receipt. | The license email, your Gumroad Library, and My Account → My Licenses on bedigit.com |
| Envato Market CodeCanyon |
Issued by Envato, not by us, and never sent by email: you download it yourself from your Envato account. | Envato account → Downloads → License certificate & purchase code |
1. bedigit.com Store (in-site purchase)
- As soon as the order’s payment status becomes Paid, a license key is generated automatically for every licensed item in the order (one key per purchased unit: buying 3 units gives 3 distinct keys).
- It is emailed to the address used on the order, either in a dedicated license email or inside the order confirmation email. Check your inbox and your spam / junk folder.
- The key stays available in your account under My Account → My Licenses. Keys are masked in the list; open the license detail page to reveal and copy the full key, see the domains it is activated on, and deactivate a domain to free an activation slot.
- The matching invoice is under My Account → My Orders.
2. Gumroad
- A Gumroad purchase produces two separate emails: the Gumroad receipt (sent by Gumroad, giving access to the files) and a license key email (sent by bedigit.com) that contains your purchase code.
- The license key email is generated as soon as Gumroad notifies us of the sale, so it normally arrives within seconds of the payment. Here too, check your inbox and your spam / junk folder.
- When the Gumroad product uses Gumroad’s own license-key feature, the same key also appears in your Gumroad receipt and under Library → your purchase on gumroad.com.
- Use the same email address on bedigit.com as on Gumroad: your keys are then linked to your account automatically and listed under My Account → My Licenses, even if you register after the purchase. You can also add a Gumroad key manually from My Account → My Gumroad Licenses.
3. Envato Market (CodeCanyon)
- Envato purchase codes are issued and delivered by Envato Market, never emailed by us, so there is nothing to look for in your spam folder: you retrieve the code from your Envato account.
- Log in to your Envato / CodeCanyon account, open the Downloads page, find the item, and choose License certificate & purchase code from the Download dropdown. The code is written in that certificate.
- An Envato purchase code looks like
12345678-90ab-cdef-1234-567890abcdef(8-4-4-4-12 characters). It never changes, and renewing item support does not issue a new one. - Official Envato article: Where Is My Purchase Code?
Configuration
All settings are managed in Admin → PayPal → Settings (stored in the settings table, group paypal).
| Setting | Description | Default |
|---|---|---|
paypal_mode |
API mode: sandbox for testing or live for production payments. |
sandbox |
paypal_client_id |
PayPal REST API Client ID. Stored encrypted in the database. | (empty) |
paypal_client_secret |
PayPal REST API Client Secret. Stored encrypted in the database. | (empty) |
paypal_webhook_id |
PayPal Webhook ID for verifying incoming webhook event signatures. Stored encrypted. | (empty) |
paypal_currency |
ISO 4217 currency code used for PayPal transactions (e.g. USD, EUR, GBP). | USD |
paypal_brand_name |
Brand name displayed on the PayPal checkout page (max 127 characters). | (app name) |
Database Settings → Config Mapping
Settings stored in the database override the config file defaults at boot time via the service provider:
| Database Key | Config Key | Encrypted? |
|---|---|---|
paypal_mode |
paypal.mode |
No |
paypal_client_id |
paypal.{mode}.client_id |
Yes |
paypal_client_secret |
paypal.{mode}.client_secret |
Yes |
paypal_webhook_id |
paypal.webhook_id |
Yes |
paypal_currency |
paypal.currency |
No |
paypal_brand_name |
paypal.brand_name |
No |
paypal_client_id and paypal_client_secret are stored
against the currently active mode. If mode is sandbox, they map to paypal.sandbox.client_id
and paypal.sandbox.client_secret.
Environment Variables
Getting PayPal Credentials
- Go to developer.paypal.com/dashboard and log in with your PayPal Business account.
- Navigate to Apps & Credentials.
- Click Create App (or select an existing app).
- Copy the Client ID and Client Secret from the app details page.
- For sandbox testing, toggle to the Sandbox tab to get sandbox credentials.
- For webhooks, go to Webhooks in the dashboard, create a webhook pointing to
https://yoursite.com/paypal/webhook, and copy the Webhook ID.
Required Webhook Events
When creating your PayPal webhook, subscribe to these events:
PAYMENT.CAPTURE.COMPLETED: payment was successfully capturedPAYMENT.CAPTURE.DENIED: payment capture was deniedPAYMENT.CAPTURE.REFUNDED: a refund was processed
localhost). Use a tunnel service like ngrok for local testing.
Admin: Settings
The settings page (PayPal → Settings) is organized into two sections:
API Credentials
- Client ID: masked password field with show/hide toggle. Your PayPal REST API Client ID.
- Client Secret: masked password field with show/hide toggle. Stored encrypted in the database.
- Webhook ID: masked password field with show/hide toggle. Used for verifying webhook signatures. Optional but recommended.
Crypt::encryptString()
before being saved to the settings table. They are decrypted only when displayed in the form or when
configuring the PayPal API client. Leave fields empty to keep current values.
Payment Options
- Mode: dropdown to select
Sandbox (Testing)orLive (Production). Controls which set of API credentials is used. - Currency: three-character ISO 4217 currency code (e.g. USD, EUR, GBP). Used as the default currency for PayPal orders.
- Brand Name: the name shown on the PayPal checkout page (max 127 characters). Falls back to the application name if empty.
A help card at the top of the settings page provides direct links to:
Checkout Flow
The PayPal payment flow follows the standard redirect-based checkout pattern:
- Customer selects PayPal: during shop checkout, the customer chooses PayPal as their payment method.
- Order creation: the shop calls
PaypalGateway::createPaymentIntent($order), which creates a PayPal order via the REST API withCAPTUREintent. - Local record: a record is saved to the
paypal_orderstable with the PayPal Order ID, amount, currency, approval URL, and the polymorphic payable reference. - Redirect to PayPal: the customer is redirected to PayPal’s hosted checkout page
(the
approval_urlfrom the API response). - Customer approves: the customer logs into PayPal, reviews the order, and clicks “Pay”.
- Return to site: PayPal redirects the customer back to
/paypal/return?token={paypal_order_id}. - Payment capture: the
PaypalController::return()method callsPaypalGateway::confirmPayment()to capture the authorized payment. - Order completion: if capture succeeds, the order is marked as paid, a transaction record is created, and the customer is redirected to the success page.
Cancellation
If the customer clicks “Cancel” on the PayPal checkout page, they are redirected to
/paypal/cancel. The controller redirects them back to the shop checkout page with a
“Payment cancelled” warning message.
Payment Confirmation
When a payment is captured successfully, the gateway performs these actions:
- Updates the
paypal_ordersrecord with:status = COMPLETED,capture_id,payer_id,payer_email, andconfirmed_at. - Calls
$payable->markAsPaid('paypal', $captureId)on the order model. - Creates a
Transactionrecord in theshop_transactionstable with:gateway = 'paypal'gateway_transaction_id = {capture_id}status = 'completed'type = 'payment'- Metadata including
paypal_order_id,payer_id, andpayer_email
Refunds
The gateway supports full and partial refunds via PaypalGateway::refund().
Refund Process
- The admin initiates a refund from the shop order management.
- The gateway calls PayPal’s
refundCapturedPayment()API using the original capture ID. - If successful, a new
Transactionrecord is created withtype = 'refund'. - The order status is updated if the refund covers the full amount.
Refund Statuses
| Status | Description |
|---|---|
COMPLETED |
Refund processed immediately. |
PENDING |
Refund is pending (e.g. eCheck payments). A PAYMENT.CAPTURE.REFUNDED webhook will confirm it later. |
Webhook Setup
PayPal webhooks provide asynchronous payment event notifications. They serve as a safety net to confirm payments even when the customer’s return redirect fails.
Webhook URL
Configure PayPal to send webhook events to:
This endpoint is CSRF-exempt and does not require authentication.
Configuration
- Go to PayPal Developer Dashboard → Webhooks.
- Click Add Webhook.
- Enter your webhook URL.
- Select the three required events (see below).
- Copy the generated Webhook ID and paste it in Admin → PayPal → Settings.
Updating
There are two ways to update this add-on: via the admin panel (recommended) or manually replacing files.
Method 1: Admin Panel Upload (Recommended)
- Download the latest
.zipfile of this add-on. - Go to Admin panel → Add-ons and click the Upload button.
- Select or drag the
.zipfile into the upload area. - A confirmation prompt will show the current and new version numbers. Click Replace to proceed.
- Go to Admin panel → System Update (
/admin/update) to apply any pending database migrations.
Method 2: Manual File Replacement
Step 1: Replace Files
Replace the add-on directory with the new version.
Step 2: Run Migrations
php artisan migrate
Pending migrations run once, so the command is safe to repeat.
Step 3: Clear Caches
php artisan config:clear
php artisan route:clear
php artisan view:clear
Step 4: Verify
Visit PayPal → Settings and confirm your API credentials are still configured. Try a sandbox test payment to ensure everything works correctly.
Uninstallation
Switching an add-on off without losing anything is a deactivation: go to Admin panel → Add-ons, find PayPal Payment Gateway and click Deactivate.
- Its routes, views, admin menu entries and permissions stop being registered, and its front-end pages stop answering.
- Its database tables and all the data they hold are kept, and its files stay under
extensions/addons/paypal/. Nothing is deleted. - The purchase code recorded at activation is kept too, so activating the add-on again does not ask for it.
- Deactivation is refused while another active add-on depends on this one: deactivate that add-on first.
Click Activate on the same card to switch it back on. Pending migrations are re-run, assets are republished, and the add-on picks up exactly where it left off.
Removing
Removing is permanent and destroys the add-on's data. The Remove button only appears on a deactivated add-on, so removal is always two steps:
- Deactivate PayPal Payment Gateway (see Uninstallation).
- Click Remove on its card and confirm the prompt.
The admin panel then, in one pass:
- runs the add-on's uninstall hook, if it ships one, while its code is still on disk;
- revokes the permissions declared in its
addon.json; - rolls back its migrations (this drops its database tables and every row they hold) and purges its entries from the
migrationstable, so a later reinstall migrates from scratch; - deletes its published assets:
public/addons/paypal/,public/vendor/paypal/andstorage/app/public/addons/paypal/; - deletes the add-on directory
extensions/addons/paypal/; - deletes its row in the
addonstable (the recorded purchase code goes with it) and clears the application cache.
Removal is refused, with an explanatory message and before anything is destroyed, when the add-on is still active, when another active add-on depends on it, or when the web server (PHP) user cannot delete extensions/addons/paypal/. In that last case, give that user write permission on the directory and on its parent, then try again.
Deleting the folder over FTP or SSH is not equivalent: the add-on's tables, its entries in the migrations table and its addons row are all left behind, and its card stays in the list. Use Remove in the admin panel instead.
Troubleshooting
“PayPal API credentials are not configured”
- Ensure you have entered both the Client ID and Client Secret in Admin → PayPal → Settings.
- Verify the correct Mode is selected: sandbox credentials do not work in live mode and vice versa.
- Check that the credentials are for the correct mode (sandbox vs. live).
“PayPal authentication failed”
- Double-check that the Client ID and Client Secret are correct (no extra spaces or line breaks).
- Ensure your PayPal app is not suspended or deleted.
- Verify your server can reach
api-m.sandbox.paypal.com(sandbox) orapi-m.paypal.com(live) over HTTPS. - Check server logs for detailed error messages from the PayPal API.
Customer redirected to checkout but payment not captured
- The return URL may not have been reached (customer closed browser). Check if the webhook received
a
PAYMENT.CAPTURE.COMPLETEDevent. - Ensure the webhook URL is correctly configured in the PayPal Developer Dashboard.
- Verify the
paypal_ordersrecord was created (check thestatuscolumn).
Webhooks not being received
- Verify the webhook URL is publicly accessible over HTTPS.
- Check the PayPal Developer Dashboard → Webhooks → Events for delivery status.
- Ensure the webhook is not behind IP-based firewall rules that block PayPal’s servers.
- For local development, use a tunnel service (e.g. ngrok) to expose your local server.
Webhook signature verification failing
- Ensure the Webhook ID in admin settings matches the one in the PayPal Developer Dashboard.
- If you recently recreated the webhook, update the Webhook ID in your settings.
- Leave the Webhook ID empty to disable signature verification (not recommended for production).
Refund fails: “Refund failed”
- Ensure the original payment was captured (status
COMPLETED). - Check that the refund amount does not exceed the original payment amount.
- PayPal may reject refunds for payments older than 180 days.
- Check server logs for the specific PayPal API error message.
Orders stuck in CREATED or APPROVED status
- The customer may have approved the payment but the capture failed. Check server logs for errors during
confirmPayment(). - Try processing the capture manually via the PayPal Merchant Dashboard.
- Ensure the
srmklive/paypalpackage is up to date.
“Array to string conversion” errors
- This typically occurs when the
srmklive/paypallibrary receives unexpected config keys. The gateway filters config to only pass supported keys. Ensure you are using a compatible version of the package. - Clear the config cache:
php artisan config:clear
PayPal Payment Gateway v1.0.0: Part of the Larapen CMS platform.
© BeDigit. All rights reserved.