Contents
1 - Introduction 2 - Installation into Laravel 3 - Taking a Payment as an Order using the Order Builder 4 - Retrieving, Authorizing & Capturing an Order 5 - Handling PayPal Webhooks 6 - Manually Interacting with PayPal WebhooksTaking a Payment as an Order using the Order Builder
Published: May 25, 2024
Author: Andrew Arscott
The Laravel PayPal package utilisers builders to help us craft the requests we need to make to PayPal in order to complete a function. Using these builders we can easily add all of the information we need to quickly generate an order. For example:
$experienceContext = ExperienceContext::make()
->setBrandName(config('app.name'))
->setShippingPreference(ShippingPreferenceEnum::NO_SHIPPING)
->setUserAction(UserActionEnum::PAY_NOW)
->setReturnUrl(route('checkout.success', ['order' => $uuid, 'transaction' => $transactionUuid]))
->setCancelUrl(
route(
'checkout',
[
'status' => 'cancelled',
'order' => $uuid,
'transaction' => $transactionUuid,
]
),
);
$order = Order::builder()
->setIntent(PaymentIntentEnum::CAPTURE)
->setPaymentSource(
Paypal::make()
->setExperienceContext($experienceContext)
->setEmailAddress($user->email)
)
->addPurchaseUnit(
PurchaseUnit::make()
->setReferenceId($transactionUuid)
->setAmount(10.00, 'GBP')
)
->create();
$paypalRedirectLink = $order->getPaymentRedirectUrl();
The example above will generate us an order in paypal and we can now redirect the user to the $paypalRedirectLink for them to make their payment.
Let's go through code so we can understand the elements we need to create this order.
$order Order::builder()
This line will return an instance of the OrderBuilder class. This class is used to build and return an instance of Order.
This interface is supported by strong types and enums, so you can easily see the type of acceptable data to be passed through to a method.
->setIntent(PaymentIntentEnum::CAPTURE)
An order requires an intent, the two valid options for this are CAPTURE or AUTHORIZE. Capture means you intend to debit the funds from your customers account, whereas, Authorize will just authorize the transaction. If you are handling a transaction like someone purchasing an item from an online store where there is no chance the purchase might not go through, then capture is likely the correct option.
If you need to check that the user is able to make a payment, but then need to make verification checks before actually charging them, then Authorize might be the better option. A good example of this is Deliveroo. Deliveroo will authorize the payment for your order before they submit it to the restaurant to accept your order. If the restuarant does not accept the order, the authorization will be cancelled and no money will have been taken from the customers account, however, if they accept, a capture will then take place to debit the funds.
Next, we need to select a payment source:
->setPaymentSource(
Paypal::make()
->setExperienceContext($experienceContext)
->setEmailAddress($user->email)
)
At the time of writing, this package only supports Paypal and Token as a payment source. Many other sources area available, such as Venmo, but they have not been implemented yet. If you'd like to see a particular payment source implemented, please open an issue or drop us a message.
A payment source will decide how the order will be funded, in this case, PayPal is the payment source, which will likely be the most common flow for many online shops as this loads the hosted paypal payment screen.
Most, if not all payment sources will need to have an exerpience context set as well as some additional payment source specific detail, for example, in this instance, we pass the user's email address to PayPal which prefills it in PayPal.
The experience context is used to determine the type of journey the user will have when using a particular payment source:
$experienceContext = ExperienceContext::make()
->setBrandName(config('app.name'))
->setShippingPreference(ShippingPreferenceEnum::NO_SHIPPING)
->setUserAction(UserActionEnum::PAY_NOW)
->setReturnUrl(route('checkout.success', ['order' => $uuid, 'transaction' => $transactionUuid]))
->setCancelUrl(
route(
'checkout',
[
'status' => 'cancelled',
'order' => $uuid,
'transaction' => $transactionUuid,
]
),
);
In the case of the hosted paypal order checkout, we set the brand name, which would be the shop name, this is shown on the order page, which is helpful for customers to ensure they are in the right place.
Additionally, the shipping preference, which controls if the hosted Paypal form should collect the shipping address for the customer, to be returned later on as part of the authorization and capture of the order. In most cases, you'd not need to collect this via paypal, as your own checkout will likely handle collecting this data, however, this option allow you to specfiy if PayPal should get the shipping from the file, if there is no shipping, or if they need to set the address for shipping.
The user action can be set to either Continue or Pay Now. Pay now will usually be the final point in a transaction where we charge the customer and then redirect them to a payment success page, where as continue will return the user to a point in their checkout journey to do more actions before the payment is finally captured fully. This might be useful if you need to verify the users payment method before performing another action, like booking an appointment time etc.
Finally, setting the return and cancel URL provide the hosted script somewhere to send the user when they either complete the form succesfully, or cancel the checkout.
Once the experience context is added, we can begin to add Purchase Units. These represent a contract between the store and the customer describing what will be charged and what they are buying. At the time of writing, you are only able to set a reference ID, amount and soft descriptor. Further improvements to support item breakdown will be added soon.
Now you have created your order, you can call the create method which will make a request to PayPal to generate the order and return an instance of Order. From here, you will be able to retrieve the redirect link to send the customer to the relevant page.