405 Message on cartCreate mutation

Topic summary

A developer encountered a 405 Method Not Allowed error when attempting to execute a cartCreate mutation from the client side while building a headless Shopify store.

Key Details:

  • The mutation worked successfully from the backend but failed on the client side
  • The developer was using the Storefront API (a public API) with POST requests
  • Code included a GraphQL mutation for cart creation and an “Add to Cart” button handler in React/Next.js

Resolution:
The issue was resolved by correcting environment variable configuration (.env file setup). The problem was not related to API permissions or request methods, but rather improper environment variable handling that prevented proper client-side authentication or API endpoint configuration.

Summarized with AI on November 20. AI used: claude-sonnet-4-5-20250929.

Apologies if I’m displaying my ignorance, but I’m stuck on this currently. Creating my first headless Shopify store and I can’t get my cartCreate mutation to work from the client side. It works from my backend, but receives a 405 Method Not Allowed response when sending my mutation from the client.

I was under the impression that the Storefront API is a public API and that all queries/mutations are POST requests, so it’s not my request method and it isn’t my permissions, right? I’m following other examples and they seem to make it work from the client side, so what am I doing wrong here?

Here’s my mutation function:

export const addToCart = async (itemId, quantity) => {
  const createCartMutation = gql`
  mutation createCart($cartInput: CartInput) {
    cartCreate(input: $cartInput) {
      cart {
        id
      }
    }
  }
  `;

  const variables = {
    cartInput: {
      lines: [
        {
          quantity: parseInt(quantity),
          merchandiseId: itemId,
        },
      ],
    },
  };

  try {
    return await graphQLClient.request(createCartMutation, variables);
  } catch (error) {
    throw new Error(error);
  }
};

And here’s where I call it in my Add To Cart Button (React w/ Next.js):

const AddToCartBtn = ({ productId, quantity }) => {
  const [ buttonText, setButtonText ] = useState('Add to Cart');
  useEffect(() => {
    console.log('add to cart', productId)
  })

  const handleAddToCart = async () => {

    let cartId = sessionStorage.getItem("modSquidCartId");
    console.log('cartId', cartId)
    if (quantity > 0) {
      if (cartId) {
        await updateCart(cartId, productId, quantity);

      } else {
        let data = await addToCart(productId, quantity);
        cartId = data.cartCreate.cart.id;
        sessionStorage.setItem("modSquidCartId", cartId);
      }
    }
  };

  return ;
};

Thanks for any and all help and guidance.

SOLVED. I was messing up my environment variables. FALSE ALARM.