Headless and GraphQL

Build your own checkout on a PWA or custom storefront, with Magento and Buckaroo handling payments behind it.

📘

This page is for developers building a custom storefront. If you use the standard Magento checkout or Hyvä, you don't need any of this. See Additional modules.

How it works

In a headless setup your frontend talks to Magento over GraphQL. The Buckaroo GraphQL module adds the payment-related queries and mutations to that API, so your frontend can:

  1. Fetch the payment methods available for the current cart.
  2. Set a payment method on the cart, along with any method-specific data.
  3. Place the order and receive a redirect URL where required.
  4. Return the customer to your storefront after payment.

The server-side payment flow is unchanged. Buckaroo still sends push messages to your Magento backend, and Magento still owns order status. Your frontend is only responsible for collecting input and handling the redirect.


Install

Install the base plugin first, then:

composer require buckaroo/magento2graphql
php bin/magento setup:upgrade
php bin/magento setup:di:compile
php bin/magento cache:flush

Requirements

  • Buckaroo Magento 2 plugin installed and configured with valid keys.
  • Payment methods enabled in the Magento admin. The GraphQL API respects the same configuration as the Luma checkout. A method that's Off in the admin will not be returned by the API.
  • Buckaroo's push IPs allowlisted on your Magento backend, since the push goes there rather than to your storefront. See Connect your Buckaroo account.
  • A return URL on your storefront where customers land after payment.
⚠️

The push and the return go to different servers. The plugin sends the push URL automatically and it points at Magento; the return URL points at your frontend. In a headless setup it's your Magento backend that needs to be reachable by Buckaroo, which is easy to overlook when your storefront is the only thing you think of as "the site".


Schema reference

The module adds Buckaroo-specific queries and mutations, and extends three core Magento types.

Extensions to core types

Three core Magento types gain a Buckaroo field:

TypeFieldPurpose
AvailablePaymentMethodbuckaroo_additionalExtra data for a method, for example the list of bank issuers to render
PaymentMethodInputbuckaroo_additionalMethod-specific input you send when setting the payment method
Orderbuckaroo_additionalRedirect URL, transaction ID, and any fields needed for inline payments

Payment flow

1. Set your return URL so the customer comes back to your storefront:

mutation {
  setBuckarooReturnUrl(input: {
    cart_id: "..."
    return_url: "https://your-storefront.com/checkout/result"
  }) { success }
}

2. Read the available methods, including whatever extra input each one needs:

query {
  cart(cart_id: "...") {
    available_payment_methods {
      code
      title
      buckaroo_additional {
        key
        value
        values { name code img }
      }
    }
  }
}

values is what you render as a dropdown: bank issuers for Wero, card brands for credit cards.

3. Set the method, passing method-specific input under buckaroo_additional:

mutation {
  setPaymentMethodOnCart(input: {
    cart_id: "..."
    payment_method: {
      code: "buckaroo_magento2_ideal"
      buckaroo_additional: { buckaroo_magento2_ideal: { issuer: "ABNANL2A" } }
    }
  }) { cart { selected_payment_method { code } } }
}

Every supported method has its own input type. Some need only an issuer; Buy Now Pay Later methods require more, such as customer_DoB, customer_telephone and termsCondition. Card payments via buckaroo_magento2_creditcards expect customer_encrypteddata, which the Buckaroo JS SDK produces from the Hosted Fields form. Raw card details never pass through your own code.

4. Place the order and read the redirect:

mutation {
  placeOrder(input: { cart_id: "..." }) {
    order {
      order_number
      buckaroo_additional {
        redirect
        transaction_id
        data { key value }
      }
    }
  }
}

Send the customer to redirect when it's present. For inline methods it will be empty and data carries the fields you need instead.

5. Check the result when the customer returns:

mutation {
  buckarooPaymentTransactionStatus(input: { transaction_id: "..." }) {
    payment_status
    status_code
  }
}

Giftcards and vouchers

Partial payments are handled with their own mutations, since an order can be part-paid by giftcard and settled with another method:

  • getBuckarooGiftcardTransactions returns what's been paid so far, the remaining amount, and which methods can cover it
  • buckarooProcessGiftcardTransaction applies a giftcard using giftcard_id, card_number and card_pin
  • buckarooProcessVoucherTransaction applies a voucher code

iDIN age verification

  • getBuckarooIdin returns whether iDIN is active, whether this session is already verified, and the available issuers
  • verifyBuckarooIdin starts verification and returns a redirect to send the customer to
📘

The schema lives in etc/schema.graphqls in the GraphQL module. Introspect your own endpoint for the definitive list, since the available methods depend on which ones you have enabled and on your Buckaroo contract.


Handling the return

After payment, the customer returns to your storefront. Do not treat the return as confirmation of payment. The customer may return before the push has been processed, or may not return at all while the payment still succeeds.

The correct pattern:

  1. Show a neutral "processing your payment" state on return.
  2. Poll Magento for the order status, or wait for your own backend to be notified.
  3. Show the final result once Magento reflects it.

What you build yourself

Most of the plugin works the same regardless of storefront, but anything that renders inside the Magento checkout is your responsibility in a headless setup:

  • Express checkout buttons: Apple Pay, Google Pay and PayPal need implementing in your storefront.
  • GA Client ID tracking: this reads browser cookies and passes them through the payment redirect, so you'd handle it in your own frontend code.

Server-side features are unaffected. Second Chance, refunds, order statuses and push handling all run in Magento and behave normally.


Narrowing down a problem

In a headless setup the plugin handles the backend (API requests, authentication and the payment lifecycle) while your storefront handles everything the customer sees. When something breaks, working out which side it's on saves a lot of time.

The quickest test is to reproduce the same order on a standard Luma checkout. If it fails there too, it's in the plugin or the configuration. If it only fails on your storefront, it's in the frontend.


Did this page help you?