Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Paypal Pro Checkout Nvp Laravel Package

payum/paypal-pro-checkout-nvp

Payum gateway for PayPal Payments Pro using the legacy NVP (Name-Value Pair) API, enabling direct credit card payments and recurring profiles through PayPal Pro Checkout. Integrates with Payum's payment abstraction for Laravel and PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

What it is. A Payum gateway that talks to PayPal's legacy NVP (Name-Value Pair) API for PayPal Payments Pro — i.e. a card-not-present form where you POST the card fields from your own checkout page (DoDirectPayment semantics), not a PayPal-hosted redirect. If you actually want the "redirect to PayPal, come back with a token" flow, you want payum/paypal-express-checkout-nvp instead.

Viability check before you commit. Last release 2016, 3 stars, 0 dependents, and it pins old payum/core constraints. Run these first:

composer show --all payum/paypal-pro-checkout-nvp   # see requires + available versions
composer why-not payum/paypal-pro-checkout-nvp ^1.0 # what's blocking install

If you're on Payum 2.x or PHP 8+, expect to either pin an older Payum or vendor the Api class into your own gateway. Decide that before writing checkout code.

Install and configure.

composer require payum/paypal-pro-checkout-nvp

Plain Payum:

$payum = (new \Payum\Core\PayumBuilder())
    ->addDefaultStorages()
    ->addGateway('paypal_pro', [
        'factory'   => 'paypal_pro_checkout_nvp',
        'username'  => getenv('PAYPAL_PRO_USERNAME'),
        'password'  => getenv('PAYPAL_PRO_PASSWORD'),
        'signature' => getenv('PAYPAL_PRO_SIGNATURE'),
        'sandbox'   => true,
    ])
    ->getPayum();

$gateway = $payum->getGateway('paypal_pro');

Symfony/PayumBundle:

payum:
    gateways:
        paypal_pro:
            factory: paypal_pro_checkout_nvp
            username: '%env(PAYPAL_PRO_USERNAME)%'
            password: '%env(PAYPAL_PRO_PASSWORD)%'
            signature: '%env(PAYPAL_PRO_SIGNATURE)%'
            sandbox: true

Where to look first, in this order:

  1. src/Payum/Paypal/ProCheckout/Nvp/PaypalProCheckoutNvpGatewayFactory.php — confirms the factory name paypal_pro_checkout_nvp and which config keys (username, password, signature, sandbox) actually exist.
  2. src/Payum/Paypal/ProCheckout/Nvp/Api.php — the whole NVP surface in one file. This tells you definitively whether you get doDirectPayment only, or also doCapture, refundTransaction, etc.
  3. src/Payum/Paypal/ProCheckout/Nvp/Action/* — how Capture/Authorize requests get translated into NVP parameters and how ACK/errors are surfaced.
  4. Tests/ApiTest.php — the fastest documentation you'll find: it shows the exact NVP parameter names the class emits.

First use case — take a card payment. Fill the payment model's details with the Pro billing/card fields, then Capture:

use Payum\Core\Request\Capture;
use Payum\Core\Model\Payment;

$payment = new Payment();
$payment->setNumber('ORDER-1042');
$payment->setTotalAmount(1999);      // minor units
$payment->setCurrencyCode('USD');
$payment->setDetails([
    'FIRSTNAME'      => 'John',
    'LASTNAME'       => 'Doe',
    'STREET'         => '1 Main St',
    'CITY'           => 'San Jose',
    'STATE'          => 'CA',
    'ZIP'            => '95131',
    'COUNTRYCODE'    => 'US',
    'CREDITCARDTYPE' => 'Visa',
    'ACCT'           => '4111111111111111',
    'EXPDATE'        => '122030',    // MMYYYY, no slash
    'CVV2'           => '123',
    'IPADDRESS'      => $request->getClientIp(),
]);

$gateway->execute(new Capture($payment));

// Inspect $payment->getDetails() for ACK, TRANSACTIONID, L_ERRORCODE0...

Implementation Patterns

Treat details as the NVP envelope. This gateway is thin: whatever you put in details is merged into the request, and whatever PayPal returns is merged back. Use UPPERCASE PayPal parameter names consistently and keep your own application data (order id, customer id) under lowercase custom keys or in a separate column so you never collide with PayPal's namespace.

Direct-capture vs. authorize-then-capture. DoDirectPayment supports PAYMENTACTION=Authorization followed by DoCapture, which matters if you ship physical goods and want to capture on dispatch. Check whether the shipped actions map Capture to Sale unconditionally; if so, either accept immediate settlement or write a small action that sets PAYMENTACTION explicitly. Don't assume two-step works until you've read the action.

Never persist raw card data. The Payment model's details array gets serialized into your token/payment storage. Strip or mask ACCT, CVV2, EXPDATE after capture, or wrap them in Payum's sensitive-value wrapper (Payum\Core\Security\SensitiveValue if your Payum version ships it) so they're masked in dumps and refused by the serializer. Verify with a SELECT on the stored row before going anywhere near production.

Store the transaction identity, not just a boolean. Persist TRANSACTIONID, CORRELATIONID, ACK, AMT, CURRENCYCODE, and TIMESTAMP on your order. When a support ticket arrives three weeks later, TRANSACTIONID is the only handle PayPal support will accept. CORRELATIONID is what PayPal engineering uses to trace a request — log it on every failure.

Testing. Two layers:

  • Unit: build the gateway with a stub Api (override the api instance in the gateway config, or construct the gateway manually and setApi()), assert your code emits the right details and handles ACK => Failure without exploding.
  • Integration: sandbox => true against a sandbox seller account that actually has Payments Pro enabled — a vanilla sandbox account will reject you with error 10501.

Symfony integration. Keep the gateway call inside a service, not a controller, because the Capture request needs the client IP (required for IPADDRESS) and you don't want controllers reaching into the HTTP foundation for that. Return an order status object; let the controller render.

Reconciliation job. Because there's no webhook, poll. A nightly job that re-queries uncertain transactions (timeouts, ACK unknown) and matches on TRANSACTIONID is not optional — it is the only way this integration stays correct.

Gotchas and Tips

The package is effectively unmaintained. Last release 2016. The practical consequence is dependency hell, not broken code — the Api class is simple string-building and will keep working long after the package metadata rots. If composer won't resolve, the cheapest fix is usually to copy Api.php plus your one action into App\Payum and register your own gateway factory, rather than fighting version constraints.

You're in PCI scope. Card numbers transit your server. This is SAQ D territory, not SAQ A. If that's a problem organisationally, this package is the wrong choice — use a hosted-fields or REST-with-tokenisation integration where the PAN never touches your infrastructure.

IPADDRESS is mandatory. DoDirectPayment requires the buyer's IP; omit it and you get a generic "there's an error with this transaction" with no useful hint. In dev with no request context, pass a fixed placeholder rather than letting it be null.

Format traps. EXPDATE is MMYYYY with no separator (122030, not 12/2030, not 2030-12). AMT must be a dot-decimal string; Payum converts your minor-unit totalAmount for you, but if you set AMT in details yourself it will not be re-converted. Currency must be one the merchant account is provisioned for.

Error handling. PayPal returns ACK of Success, SuccessWithWarning, or Failure, plus indexed L_ERRORCODE0..n / L_SHORTMESSAGE0..n / L_LONGMESSAGE0..n. Catch the exception the Api throws, then re-read the raw response from details — the exception message alone usually drops the long message, which is where the real cause lives. Codes you'll meet: 10501 (merchant not configured for Pro), 10502 (card expired), 10507 (CVV2 mismatch), 10527 (invalid data — almost always a malformed field), 10417 (instruct customer to use another payment method), 15005 (processor declined).

No refund, void, recurring, or 3-D Secure support ships here. These are the extension points you'll actually need:

  • Refunds/voids: add an action that calls NVP RefundTransaction / DoVoid through the same credentials, registered on your own gateway factory (populateGateway() → parent::populateGateway($gateway) then $gateway->addAction(...)).
  • 3-D Secure: Payments Pro can return MPI data via RETURNFMFDETAILS, but nothing in this package handles the ACS redirect. Budget real time for it, or scope it out explicitly.
  • Recurring: CreateRecurringPaymentsProfile is not wrapped; you'd be writing raw NVP.

No idempotency key. Retrying a timed-out DoDirectPayment can double-charge. Decide on a policy now: on timeout, don't retry — mark the order pending_review and reconcile by querying TRANSACTIONID/searching the day's transactions before re-attempting.

Debug by dumping the NVP pair. When a request fails opaquely, log the outgoing parameter string with card fields masked and the raw response body. Nine out of ten failures are a typo'd parameter name or a missing required address field, and the full pair makes it obvious in seconds.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource