Headless Direct to Checkout without Cart

I’m having trouble with creating a headless straight to checkout workflow.

Details: Self-hosted app developed with Next.js and server actions connecting to WIX headless ecom. For a single product, I want to create a checkout, redirect to the WIX hosted checkout page, then redirect to a confirmation page within my app. I have set up manual payment and currently have only the free plan. I am trying out WIX before adding a premium plan.

Problem:

CreateCheckout works (returns a non-null checkout ID. createRedirectSession returns an error that may indicate problems with my site setup within WIX, but I don’t understand what’s wrong. In the docs it says that I can test checkout with a free plan and manual payment using the wix-stores, not sure about wix-ecom. My code and the error I get are below.

Appreciate any suggestions. Thanks.

CODE

"use server";

import { env } from "@/env/server";
import { getWixClient } from "@/lib/wixAdminClient";
import type { CreateCheckoutResult } from "@/types/wix-ecom";

// Import the auth strategy for the relevant access type
// Import the relevant host module if needed

export async function createCheckout(
  productId: string = "cc72f660-c70f-9251-75bc-af912698c641",
  quantity: number = 1
): Promise<CreateCheckoutResult> {
  try {
    const wixClient = getWixClient();

    const options = {
      lineItems: [
        {
          quantity: 1,
          catalogReference: {
            // Wix Stores appId
            appId: "215238eb-22a5-4c36-9e7b-e7c08025e04e",
            // Wix Stores productId
            catalogItemId: productId,
          },
        },
      ],
      channelType: "WEB" as const,
    };

    console.log("Creating checkout");

    const checkoutResponse =
      await wixClient.ecom.checkout.createCheckout(options);
    const checkoutId = checkoutResponse._id;

    if (!checkoutId) {
      throw new Error("Failed to create checkout - no checkout ID returned");
    }

    console.log("Redirecting to checkout");

    const redirectSession = await wixClient.redirects.createRedirectSession({
      ecomCheckout: { checkoutId },
      callbacks: {
        postFlowUrl: `${env.BASE_URL}/order-confirmation`, // Where to redirect after checkout
        thankYouPageUrl: `${env.BASE_URL}/order-confirmation`, // Optional: custom thank you page
      },
    });

    const checkoutUrl = redirectSession.redirectSession?.fullUrl;

    if (!checkoutUrl) {
      throw new Error("Failed to get checkout URL from redirect session");
    }

    console.log("Returning");

    return {
      success: true,
      checkoutUrl: checkoutUrl,
    };
  } catch (error) {
    console.error("Checkout creation error:", error);
    return {
      success: false,
      error:
        error instanceof Error ? error.message : "Failed to create checkout",
    };
  }
}

ERROR

Error: {“message”: “Cannot read properties of undefined (reading ‘components’)”,“details”: {“applicationError”: {“description”: “Cannot read properties of undefined (reading ‘components’)”,“code”: 500,“data”: {“requestId”: “1764257557.251574907946514080348”,“details”: {“message”: “Cannot read properties of undefined (reading ‘components’)”,“details”: {“x-wix-guest-error-bin”: “CglUeXBlRXJyb3ISOkNhbm5vdCByZWFkIHByb3BlcnRpZXMgb2YgdW5kZWZpbmVkIChyZWFkaW5nICdjb21wb25lbnRzJykakgdUeXBlRXJyb3I6IENhbm5vdCByZWFkIHByb3BlcnRpZXMgb2YgdW5kZWZpbmVkIChyZWFkaW5nICdjb21wb25lbnRzJykKICAgIGF0IGdldE9hdXRoQXBwQ29tcG9uZW50VjIgKC9vcHQvYXBwL3BhY2thZ2VzL3JlZGlyZWN0cy1hcGkvZGlzdC91dGlscy9hcHAtdXRpbHMuanM6ODU6NjIpCiAgICBhdCBwcm9jZXNzLnByb2Nlc3NUaWNrc0FuZFJlamVjdGlvbnMgKG5vZGU6aW50ZXJuYWwvcHJvY2Vzcy90YXNrX3F1ZXVlczo5NTo1KQogICAgYXQgYXN5bmMgZ2V0T2F1dGhBcHBDb21wb25lbnQgKC9vcHQvYXBwL3BhY2thZ2VzL3JlZGlyZWN0cy1hcGkvZGlzdC91dGlscy9hcHAtdXRpbHMuanM6OTM6MTIpCiAgICBhdCBhc3luYyBnZXRDbGllbnRNb2RlbCAoL29wdC9hcHAvcGFja2FnZXMvcmVkaXJlY3RzLWFwaS9kaXN0L3V0aWxzL2FwcC11dGlscy5qczoxMDA6MjkpCiAgICBhdCBhc3luYyBQcm9taXNlLmFsbCAoaW5kZXggMikKICAgIGF0IGFzeW5jIFJlZGlyZWN0U2Vzc2lvblNlcnZpY2UuY3JlYXRlUmVkaXJlY3RTZXNzaW9uICgvb3B0L2FwcC9wYWNrYWdlcy9yZWRpcmVjdHMtYXBpL2Rpc3Qvc2VydmljZXMvUmVkaXJlY3RTZXNzaW9uU2VydmljZS5qczo1MzoxNjApCiAgICBhdCBhc3luYyBBZGFwdGVyRm9yUmVkaXJlY3RTZXNzaW9uU2VydmljZS5jcmVhdGVSZWRpcmVjdFNlc3Npb24gKC9vcHQvYXBwL3BhY2thZ2VzL3JlZGlyZWN0cy1hcGkvZGlzdC9fX2dlbmVyYXRlZF9fL3dpeC9oZWFkbGVzcy92MS9BYnN0cmFjdFJlZGlyZWN0U2Vzc2lvblNlcnZpY2UuanM6MjI6ODApCiAgICBhdCBhc3luYyBBZGFwdGVyRm9yUmVkaXJlY3RTZXNzaW9uU2VydmljZS5jcmVhdGVSZWRpcmVjdFNlc3Npb24gKC9vcHQvYXBwL25vZGVfbW9kdWxlcy9Ad2l4L25zci1zZXJ2ZXIvZGlzdC9ncnBjLmpzOjkwOjI0KSIRCgRuYW1lEglUeXBlRXJyb3IiRQoHbWVzc2FnZRI6Q2Fubm90IHJlYWQgcHJvcGVydGllcyBvZiB1bmRlZmluZWQgKHJlYWRpbmcgJ2NvbXBvbmVudHMnKQ==”,“date”: “Thu, 27 Nov 2025 15:32:37 GMT”,“content-type”: “application/grpc+proto”,“failed-client.method”: “wix.headless.v1.RedirectSessionService/CreateRedirectSession”,“failed-client.options.deadline”: “9.969569627s from now”}}}},|                             ^45 |       ecomCheckout: { checkoutId },46 |       callbacks: {47 |         postFlowUrl: ${env.BASE_URL}/order-confirmation, // Where to redirect after checkout {response: [Object],requestId: ‘1764257557.251574907946514080348’,details: [Object],status: 500}

Hi all,

I found my original issue. It was related to using an “Admin” Wix client (Create a Client with an API Key) instead of a “OAuth/visitor” Wix client (Create a Client for Authentication with OAuth) Which leads me to another question. Why does the OAuth Wix client work with the ecom sdk while the admin/API key Wix client not work. If anyone knows - what are the use cases and criteria for using each.