How to

Use external payment frame

Complete checkout using an external payment provider frame with Geins Merchant API

Overview

Learn how to implement a checkout flow using an external payment provider frame. This guide covers creating a checkout session, selecting shipping, displaying the payment frame, and completing the order.

Prerequisites

  • Merchant API key
  • Existing cart with items
  • Payment provider configured with frame/iframe support

Goal

  • Create a checkout session and retrieve payment frame HTML
  • Display the payment frame in your frontend
  • Complete the cart after payment

Architecture at a glance

  • Create checkout → Select shipping → Get payment frame → Display frame → Complete cart

Step-by-step

Create checkout and get shipping options

Start by creating a checkout session. This will return available shipping and payment options.

Try it out in the GraphQL Playground using the query, headers and variables below.

Request example

mutation createOrUpdateCheckout(
  $cartId: String!
  $checkout: CheckoutInputType
  $channelId: String
  $languageId: String
  $marketId: String
) {
  createOrUpdateCheckout(
    cartId: $cartId
    checkout: $checkout
    channelId: $channelId
    languageId: $languageId
    marketId: $marketId
  ) {
    cart {
      id
      summary {
        total {
          regularPriceIncVat
        }
      }
    }
    shippingOptions {
      id
      displayName
      feeIncVat
      isSelected
    }
    paymentOptions {
      id
      displayName
      paymentType
      isSelected
      paymentData
    }
  }
}

Response example

200 OK
response.json
{
  "data": {
    "createOrUpdateCheckout": {
      "cart": {
        "id": "{CART_ID}",
        "summary": {
          "total": {
            "regularPriceIncVat": 299
          }
        }
      },
      "shippingOptions": [
        {
          "id": 1,
          "displayName": "Standard",
          "feeIncVat": 59,
          "isSelected": true
        },
        {
          "id": 7,
          "displayName": "Store pickup",
          "feeIncVat": 0,
          "isSelected": false
        }
      ],
      "paymentOptions": [
        {
          "id": 23,
          "displayName": "Klarna Checkout",
          "paymentType": "KLARNA",
          "isSelected": false,
          "paymentData": null
        },
        {
          "id": 27,
          "displayName": "Geins Pay",
          "paymentType": "GEINS_PAY",
          "isSelected": false,
          "paymentData": null
        },
      ]
    }
  }
}
The default shipping option will be pre-selected, but you must manually select the payment option to get the payment frame HTML.

Select shipping and payment options to get payment frame

Update the checkout with the selected shipping method and payment option to get the payment frame HTML.

Request example

mutation createOrUpdateCheckout(
  $cartId: String!
  $checkout: CheckoutInputType
  $channelId: String
  $languageId: String
  $marketId: String
) {
  createOrUpdateCheckout(
    cartId: $cartId
    checkout: $checkout
    channelId: $channelId
    languageId: $languageId
    marketId: $marketId
  ) {
    cart {
      id
      summary {
        total {
          regularPriceIncVat
        }
      }
    }
    paymentOptions {
      id
      name
      displayName
      paymentType
      isSelected
      paymentData
    }
  }
}

Response example

200 OK
response.json
{
  "data": {
    "createOrUpdateCheckout": {
      "cart": {
        "id": "{CART_ID}",
        "summary": {
          "total": {
            "regularPriceIncVat": 348
          }
        }
      },
      "paymentOptions": [
        {
          "id": {PAYMENT_ID},
          "displayName": "Klarna Checkout",
          "paymentType": "KLARNA",
          "isSelected": true,
          "paymentData": "<div id=\"klarna-checkout-container\"><!-- Klarna iframe HTML --></div><script>/* Klarna script */</script>"
        }
      ]
    }
  }
}

Display the payment frame

Inject the frame HTML into your checkout page. The payment provider's frame will handle customer payment processing. As long as you haven't completed the purchase in the frame, you can still update the checkout by calling createOrUpdateCheckout again.

If you update the cart by adding/removing items or adding a promo code, you must call createOrUpdateCheckout again to refresh the payment frame with the updated total.
When the customer completes payment, they will be redirected to your confirmation page via the callback URL configured in your payment provider settings.

Get and display confirmation frame

To get the confirmation frame (if your payment provider supports it), you will need your external order ID. Most likely you will have set up your callback URL to include the external order ID and other valuable information as query parameters. For example:

https://yourshop.com/checkout/confirmation?externalOrderId={EXTERNAL_ORDER_ID}&cartId={CART_ID}&paymentType={PAYMENT_TYPE}

Get the confirmation frame by calling the checkout query with the external order ID and payment type. Then, display the confirmation frame HTML on your confirmation page.

Request example

query checkout(
  $id: String!
  $cartId: String
  $paymentType: PaymentType!
  $channelId: String
  $languageId: String
  $marketId: String
) {
  checkout(
    id: $id
    cartId: $cartId
    paymentType: $paymentType
    channelId: $channelId
    languageId: $languageId
    marketId: $marketId
  ) {
    htmlSnippet
    order {
      orderId
    }
  }
}

Response example

200 OK
response.json
{
  "data": {
    "checkout": {
      "htmlSnippet": "<div id=\"klarna-checkout-confirmation\"><!-- Confirmation HTML --></div>",
      "order": {
        "orderId": "12345"
      }
    }
  }
}
The htmlSnippet field contains the confirmation frame HTML. Display this on your confirmation page. The paymentType should match the payment method used (e.g. GEINS_PAY, KLARNA, etc.).

Complete the cart

After displaying the confirmation frame, mark the cart as completed to make it read-only.

mutation completeCart(
  $id: String!
  $channelId: String
  $languageId: String
  $marketId: String
) {
  completeCart(
    id: $id
    channelId: $channelId
    languageId: $languageId
    marketId: $marketId
  ) {
    id
    completed
  }
}

Options

Session persistence

The checkout session is automatically maintained server-side. You can call createOrUpdateCheckout multiple times with the same cartId to update customer information, change shipping, or switch payment methods. The payment frame will be refreshed automatically.

Multi-market support

All mutations support optional parameters for multi-market functionality:

  • channelId: Target specific sales channels
  • languageId: Set content language
  • marketId: Target specific markets
Read more about channelId, languageId, and marketId in the how-to about using multi-market support.

Authenticated access

While authentication is not required for this mutation, including a JWT bearer token in the Authorization header can provide personalized results based on the authenticated user's context, for example personalized pricing.

To include authentication, add the JWT bearer token to your request headers:

"Authorization": "Bearer {JWT_TOKEN}"
Read more about obtaining and using JWT tokens in the guide about the authentication flow.

Common pitfalls

  • Ensure the payment provider is properly configured in your Geins backend
  • Always use HTTPS when displaying payment frames for security
  • The payment frame must be inserted into the DOM exactly as returned by the API
  • Don't forget to call completeCart on the confirmation page to finalize the order
Some payment providers require specific front end implementations to work correctly, refer to their documentation for details.
Related