# laravel-paypal: a PayPal REST client for Laravel and plain PHP

> This package wraps the PayPal REST API for Laravel 12 and 13 and, since version 3.1, for standalone PHP as well. It targets Orders v2 and Subscriptions v2 because the v1 Payments API is being sunset in January 2027, and it adds local webhook verification, a PSR-18 client switch and PayPal Fastlane.

**blendbyte/laravel-paypal** — PayPal REST API client for Laravel and standalone PHP.

- Repository: https://github.com/blendbyte/laravel-paypal
- Stars: 1,150 · Forks: 336
- Language: PHP
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/blendbyte-laravel-paypal

## One package for Laravel and for plain PHP

laravel-paypal is a PayPal REST API client for Laravel, and as of version 3.1 it works just as well in a project with no framework at all. The stated support is PHP 8.2 through 8.5 and Laravel 12 or 13, and the package has no hard dependency on Laravel.

That standalone capability is the notable change in the 3.1 line. The client can be instantiated directly and given credentials with setApiCredentials(), so a Symfony application, a Laravel Zero project or a plain PHP script can talk to PayPal without pulling a framework in. The Laravel side is still there for people who want a service provider, a published config file and the usual framework wiring.

The package is published on Packagist as srmklive/paypal, which is worth noting because the repository name and the Composer package name differ. The licence is MIT. The project also carries a disclaimer that it is an independent community project, not affiliated with, endorsed by or supported by PayPal, and that no warranty is provided beyond what the MIT licence covers.

Installation is a Composer require in either case:

```bash
composer require srmklive/paypal
```

In a Laravel application you then publish the config file, which is where the credentials and the behavioural settings live:

```bash
php artisan vendor:publish --provider "Srmklive\PayPal\Providers\PayPalServiceProvider"
```

The repository layout is conventional for a Laravel package, with src/, config/, lang/ and tests/ directories, a composer.json, a phpstan.neon.dist at level 7 and a phpunit.xml.dist, and a .coveralls.yml for coverage reporting.

## The v1 Payments API dies in January 2027

The single most consequential fact about this package is a date. PayPal is sunsetting the v1 Payments REST API, the endpoint behind /v1/payments/payment, in January 2027. Integrations that still use the old create-payment, redirect, execute-payment flow, or the classic Billing Agreements API at /v1/billing-agreements/, have a deadline.

This package already uses Orders v2 and Subscriptions v2 throughout, so the migration work is on the caller who built custom flows against the legacy endpoints or used the Express Checkout helpers from older versions. The version compatibility table makes the progression explicit: v1.0 talked to the classic NVP and SOAP APIs, deprecated since 2017, v2.0 used REST v1 Payments plus v2 Orders, v3.0 moved to REST v2 Orders and v2 Subscriptions, and v3.1 is the current line at PHP 8.2 and Laravel 12 to 13. Only v3.1 is marked as maintained.

The checkout flow in the new world creates an order, redirects the buyer, and captures afterwards. The documentation shows the shape:

```php
// 1. Create the order and redirect the buyer
$order = $provider->createOrder([
    'intent' => 'CAPTURE',
    'purchase_units' => [
        ['amount' => ['currency_code' => 'USD', 'value' => '49.99']],
    ],
    'payment_source' => [
        'paypal' => [
            'experience_context' => [
                'return_url' => 'https://example.com/paypal/return',
                'cancel_url' => 'https://example.com/paypal/cancel',
            ],
        ],
    ],
]);

// Redirect the buyer to: $order['links'][href where rel === 'payer-action']

// 2. After the buyer approves, capture the payment
$capture = $provider->capturePaymentOrder($order['id']);
$captureId = $provider->getCaptureIdFromOrder($capture); // store this
```

The capture identifier is not a detail to skip. getCaptureIdFromOrder() exists to pull the capture or transaction ID out of the order response so it can be stored against your own order record, which is the link between what PayPal did and what your database believes.

## Subscriptions v2 replaces the Billing Agreement dance

Recurring billing is the other place the v1 API shows up, and the mapping is just as direct. The old sequence created a billing agreement token and then a billing agreement. The new one adds a product, adds a billing plan, sets the return and cancel URLs and creates the subscription:

```php
// New subscriptions flow
$response = $provider->addProductById('PROD-XYAB12ABSB7868434')
    ->addBillingPlanById('P-5ML4271244454362WXNWU5NQ')
    ->setReturnAndCancelUrl('https://example.com/success', 'https://example.com/cancel')
    ->setupSubscription('John Doe', 'john@example.com');

// Redirect the buyer to: $response['links'][href where rel === 'approve']
```

The builder style is worth noticing, because it reflects how PayPal's v2 model works: a product is a thing you sell, a billing plan is the price and cadence attached to it, and a subscription is a buyer attached to a plan. If your integration previously assumed a billing agreement was a single object created in one call, this is a structural change rather than a rename, and the Subscription Helpers section is where plans can be built programmatically through the BillingPlanBuilder.

The rest of the resource coverage is broad enough that most integrations will not need raw HTTP. There are orders, payments, payouts, referenced payouts, reference transactions for billing agreements, invoices, invoice search and invoice templates, subscriptions, disputes and dispute actions, trackers, webhooks, payment method tokens, reporting, identity, partner referrals and a payment experience area. There is also a PayPal Fastlane helper, generateFastlaneClientToken(), for one-click guest checkout, and a Pay Upon Invoice option aimed at Buy Now Pay Later in Germany and Austria.

## Webhook verification without the API roundtrip

The 3.1 release added local webhook verification, and it is the feature that most affects how you write a receiver. verifyWebHookLocally() checks a webhook signature using a certificate cached in memory, with no API roundtrip.

That difference is not a micro-optimisation. A receiver that validates by asking PayPal whether a webhook is genuine has to make an outbound call for every notification, and that call sits in the path of your message processing. Local verification turns signature checking into a local operation with a cached certificate, so a burst of webhooks does not become a burst of outbound API traffic. The trade-off is that the certificate cache has to be correct, and the in-memory cache means a fresh process starts with an empty cache rather than a stale one.

The webhook area is listed alongside a broader set of notification and event endpoints, and the 3.1.1 release note also mentions typed webhooks, which suggests the event payloads arrive as typed objects rather than raw arrays.

Error handling is the other piece of the 3.1 work. The package handles errors with exceptions if you opt in, using withExceptions() to raise a PayPalApiException. That is a deliberate switch rather than the default, which suggests the default path is a softer, non-throwing style that suits Laravel's error handling conventions, and the exception mode suits code that wants to fail fast around a payment call.

## Timeouts, retries and a swappable HTTP client

A payment client is only as good as its behaviour when the network is slow, and the 3.1 line made those knobs configurable. The config file carries timeout, connect_timeout and max_retries, so you decide how long a call may take and how many times it is retried rather than inheriting a default.

The client itself is not fixed either. The package supports the PSR-18 HTTP client interface, and setClient() swaps Guzzle for any compliant client. The 3.2 release moved to Guzzle 8 and brought spec-conformant requests, security fixes and new endpoints.

For a package that handles money, the fact that the HTTP transport is an interface matters more than it does elsewhere. It means you can use a client with your own instrumentation, your own timeout stack or your own logging, and it means a Guzzle major upgrade is not something that has to reach your application code.

There is also a full Vault v3 payment method token surface in 3.1, covering setup tokens, permanent tokens, Apple Pay and Google Pay, which is what you need if you want to store a payment method rather than take a card on every checkout. Combined with the Fastlane client token, the package covers both the stored-credential and the guest-checkout path.

## A maintained line, and a licence that is deliberately modest

The release history shows how active the project is, and it shows the shape of the work. Version 3.1.0 arrived on 2026-04-16 with PSR-18 support, local webhooks, Fastlane and more than twenty fixes. Version 3.1.1 followed two days later on 2026-04-18 with smarter retries, typed webhooks and eight new helpers. Version 3.2.0 came on 2026-10-02 with Guzzle 8, spec-conformant requests, security fixes and new endpoints. The last push was on 2026-10-19.

The 3.1 release also lists a testing position that is unusual to see stated plainly: 100% test coverage with Pest v3 and v4, and static analysis at PHPStan level 7. There are separate CI workflows for tests, coverage and static analysis, so the claims are checked on every push rather than asserted once.

The licence is MIT, and the disclaimer is worth reading as a practical matter rather than boilerplate. The package is not affiliated with, endorsed by or supported by PayPal, PayPal is a registered trademark of PayPal, Inc, and there is no warranty beyond what the MIT licence covers. For a payment integration, that means you are trusting a community wrapper for a vendor you do not have a support contract with. The mitigations are structural rather than legal: the test suite and static analysis level are there to catch regressions in the wrapper, and the v2 API alignment means the underlying endpoints are PayPal's own documented ones.

If you need something different, the alternative in this space is talking to the REST API yourself with your own HTTP client. The difference in approach is that you get no helper objects, no builder chain, no local webhook verification and no Orders v2 migration path, and you keep full control of the request and response layer.

## Conclusion

Adopt laravel-paypal if you are building on Laravel 12 or 13, or on plain PHP with the standalone client, and you want a maintained wrapper over the Orders v2 and Subscriptions v2 surface rather than hand-written HTTP calls. Do not adopt it if you cannot finish moving off the v1 Payments API before January 2027, because that API is being sunset and this package only speaks v2, and do not adopt it expecting PayPal support, because the project states it is an independent community package with no warranty beyond the MIT licence. Before you start, publish and fill in the config file, decide whether you want the Guzzle client or your own PSR-18 implementation via setClient(), and read the webhook verification path, since verifyWebHookLocally() removes the API roundtrip that a naive receiver would rely on.

## FAQ

### How do I install laravel-paypal in Laravel and standalone PHP?

Run composer require srmklive/paypal in either case. In Laravel you also publish the config file with php artisan vendor:publish --provider "Srmklive\PayPal\Providers\PayPalServiceProvider", while in a plain PHP project you instantiate the client and pass credentials with setApiCredentials(), since the package has no hard dependency on Laravel.

### When does the PayPal v1 Payments API shut down, and does this package still use it?

PayPal is sunsetting the v1 Payments REST API in January 2027. This package already uses Orders v2 and Subscriptions v2 throughout, so the migration is needed by callers who built custom flows against the legacy endpoints or used the older Express Checkout helpers.

### What changed in version 3.1 of laravel-paypal?

It added standalone usage without Laravel, a PSR-18 HTTP client you can swap with setClient(), configurable timeout, connect_timeout and max_retries, opt-in exception handling with withExceptions(), local webhook verification with verifyWebHookLocally(), PayPal Fastlane support, the full Vault v3 payment method token API and getCaptureIdFromOrder().

### How do I swap the HTTP client used by laravel-paypal?

The package talks to the PSR-18 HTTP client interface, so you can swap Guzzle for any compliant client with setClient(). Version 3.2.0 moved to Guzzle 8 and added spec-conformant requests along with security fixes and new endpoints.

### Is laravel-paypal supported by PayPal?

No. The project states it is an independent community project that is not affiliated with, endorsed by or supported by PayPal, and that no warranty is provided beyond what the MIT licence covers.

## Sources

- [blendbyte/laravel-paypal on GitHub](https://github.com/blendbyte/laravel-paypal)
- [Issues](https://github.com/blendbyte/laravel-paypal/issues)
- [License: MIT](https://github.com/blendbyte/laravel-paypal/blob/main/LICENSE)
- [README](https://github.com/blendbyte/laravel-paypal/blob/main/README.md)
- [Releases](https://github.com/blendbyte/laravel-paypal/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/blendbyte-laravel-paypal
