I’ve implemented the PayPal Express Checkout for my headless Shopware 6 store following Shopware’s official example. However, I’m running into issues on the last step, where they use fetch()
to call the redirectUrl
. This approach doesn’t work for me because the redirectUrl
response is HTML and triggering a fetch on it doesn’t redirect the user to PayPal as intended.
Here’s my current workaround: Instead of using fetch()
, I redirect the user directly to the redirectUrl
. This opens the PayPal interface again for a second confirmation and while it does mark the order as paid in Shopware, it adds unnecessary steps for the user.
How can I complete the PayPal Express Checkout flow without needing to redirect to the redirectUrl for a second confirmation at PayPal? What steps should I follow to mark the order as paid in Shopware after handlePayment
without this extra redirect?
<PayPalScriptProvider
options={{
clientId: "<myClientId>",
}}
>
<PayPalButtons
createOrder={async () => {
// Create order --> PayPal
// POST /store-api/paypal/express/create-order
// return response.data.token
}}
onApprove={async (data, actions) => {
// Prepare Checkout --> PayPal
// POST /store-api/paypal/express/prepare-checkout { body: { token: data.orderId }}
// Update context --> set paymentMethodId to PayPal
// POST /store-api/account/register { body: { paymentMethodId: <paypalPaymentMethodId> }}
// Create order --> Shopware
// POST /store-api/checkout/order
// Handle Payment --> Shopware/PayPal
// POST /store-api/handlePayment
// { query: {isPayPalExpressCheckout: true, paypalOrderId: data.orderId } body: { orderId: <shopwareOrderId>, finishUrl: 'https://...', errorUrl: 'https://...' } }
// Redirect to the redirectUrl from the handlePayment endpoint --> re-confirmation at PayPal
}}
></PayPalButtons>
</PayPalScriptProvider>
In this setup, redirecting to the redirectUrl after handlePayment opens PayPal again, prompting the user to confirm the payment a second time. Only after this second confirmation does Shopware mark the order as “paid” instead of “unconfirmed.”