Simple Commerce supports accepting payments through PayPal in two forms: on-site and off-site. On-site is where the customer stays on your website for the checkout process and they see a PayPal embed where they can enter their payment information. Off-site is where you redirect the user to PayPal to complete the payment process there.
First, you'll need to add PayPal to your simple-commerce.php
config file. You will also need to pass in client_id
, client_secret
and environment
variables.
To obtain API credentials (provided you're already logged into PayPal), go to the PayPal Developers site, navigate to 'My Apps & Credentials'.
You can then create a sandbox/live application. At the end of the app creation progress, you'll be given the client_id
and client_secret
values.
'gateways' => [\DuncanMcClean\SimpleCommerce\Gateways\Builtin\PayPalGateway::class => ['client_id' => env('PAYPAL_CLIENT_ID'),'client_secret' => env('PAYPAL_CLIENT_SECRET'),'environment' => env('PAYPAL_ENVIRONMENT', 'production'),'mode' => 'offsite', // Either: offsite OR onsite],],
'gateways' => [\DuncanMcClean\SimpleCommerce\Gateways\Builtin\PayPalGateway::class => ['client_id' => env('PAYPAL_CLIENT_ID'),'client_secret' => env('PAYPAL_CLIENT_SECRET'),'environment' => env('PAYPAL_ENVIRONMENT', 'production'),'mode' => 'offsite', // Either: offsite OR onsite],],
Make sure that PAYPAL_ENVIRONMENT
is set to sandbox
while you're in development. You don't want a mess on your hands because you accidentally autofilled your REAL card details. That would be bad. 😅
It's best practice to use
.env
file for any API keys you need, rather than referencing them directly in your config file. Review Statamic Docs.
You may also specify the 'mode' to run the PayPal gateway in. You can either run it in offsite
or onsite
mode.
Here's a quick run down of how the whole process works:
To redirect the customer off to PayPal's checkout page, you can use the sc:checkout:paypal
tag.
{{ sc:checkout:paypal redirect="/thanks" error_redirect="/payment-error" }}
{{ sc:checkout:paypal redirect="/thanks" error_redirect="/payment-error" }}
However, bear in mind that where-ever you use that tag, the customer will be redirected away from your site. So it's probably best to have it sitting on it's own page.
On the return back to your site from PayPal, you can have customers redirected to seperate URLs, depending on whether the payment was successful or failed/cancelled.
The redirect
parameter on the sc:checkout:paypal
tag will handle the successful payment redirects.
Where as error_redirect
will handle any other payment states.
The payment form should be included inside your {{ sc:checkout }}
form, and any PayPal magic should also be wrapped in the {{ sc:gateways }}
tag to ensure you can make full use of your gateway's configuration values.
A rough example of a PayPal implementation is provided below.
<div id="paypal-button"></div><input id="paypal-payment-id" type="hidden" name="payment_id"><input type="hidden" name="gateway" value="DuncanMcClean\SimpleCommerce\Gateways\Builtin\PayPalGateway"><script src="https://www.paypal.com/sdk/js?client-id={{ paypal:config:client_id }}¤cy={{ result.currency_code }}"></script><script>paypal.Buttons({createOrder: () => {return Promise.resolve('{{ result.id }}');},onApprove: (data, actions) => {document.getElementById('paypal-payment-id').value = data.orderID;document.getElementById('checkout-form').submit();},}).render('#paypal-button');</script>
<div id="paypal-button"></div><input id="paypal-payment-id" type="hidden" name="payment_id"><input type="hidden" name="gateway" value="DuncanMcClean\SimpleCommerce\Gateways\Builtin\PayPalGateway"><script src="https://www.paypal.com/sdk/js?client-id={{ paypal:config:client_id }}¤cy={{ result.currency_code }}"></script><script>paypal.Buttons({createOrder: () => {return Promise.resolve('{{ result.id }}');},onApprove: (data, actions) => {document.getElementById('paypal-payment-id').value = data.orderID;document.getElementById('checkout-form').submit();},}).render('#paypal-button');</script>
Whenever a payment is made with PayPal, it needs to be able to communicate that with Simple Commerce. It does this using 'webhooks', which are essentially POST
requests sent by PayPal to your server that provide details about the payment.
Unfortunatley, PayPal offers no way for Simple Commerce to configure the webhook on your behalf, so you'll need to add it yourself.
https://example.com/!/simple-commerce/gateways/paypal/webhook
When you're going through the payment flow in your development environment, you will need to use something like Expose or Ngrok to proxy request to your local server. Otherwise, Mollie wouldn't be able to hit the webhook. You will also need to update the APP_URL
in your .env
.
PayPal themselves don't offer a set of 'test cards' like Stripe, or other common payment gateways do. Instead, you have to use fake card numbers and hope PayPal will accept them. Here's a couple we've found you can use for testing:
4485165985805957
4485250194331820
375527918910414
375363946611620
5557514931753152
5277359932030179