Remix Billing confirmationUrl: Too many redirects

I’m trying to setup recurring billing in the Remix Template. In my action I’m calling the AppSubscriptionCreate and get the confirmationUrl in the response. However, when I return a redirect to the confirmation url I get a browser error that there my store has redirected me too many times. What is the correct way to handle the redirect?

export async function action({ request }) {
  const { admin } = await authenticate.admin(request);
  const response = await admin.graphql(
    `#graphql
    mutation AppSubscriptionCreate($name: String!, $lineItems: [AppSubscriptionLineItemInput!]!, $returnUrl: URL!) {
  appSubscriptionCreate(name: $name, returnUrl: $returnUrl, lineItems: $lineItems, test: true) {
    userErrors {
      field
      message
    }
    appSubscription {
      id
    }
    confirmationUrl
  }
}`,
    {
      variables: {
        "name": "Super Duper Recurring Plan",
        "returnUrl": "http://google.com/",
        "test": true,
        "lineItems": [
          {
            "plan": {
              "appRecurringPricingDetails": {
                "price": {
                  "amount": 10,
                  "currencyCode": "USD"
                },
                "interval": "EVERY_30_DAYS"
              }
            }
          }
        ]
      }
      
,
    }
  );

  const responseJson = await response.json();
return redirect(responseJson.data.appSubscriptionCreate.confirmationUrl, 301)

}

2 Likes

Hy there, did you find any solution for this?

Same error here :waving_hand:

I tried to use different redirect code and throw instead of return but it didn’t worked

export const action = async ({ request }) => {
  const formData = await request.formData();
  const quantity = formData.get("quantity");
  console.log(quantity);
  // Query
  const { admin } = await authenticate.admin(request);
  let mutation = await admin.graphql(
      `#graphql
      mutation AppPurchaseOneTimeCreate($name: String!, $price: MoneyInput!, $returnUrl: URL!) {
        appPurchaseOneTimeCreate(name: $name, returnUrl: $returnUrl, price: $price) {
          userErrors {
            field
            message
          }
          appPurchaseOneTime {
            createdAt
            id
          }
          confirmationUrl
        }
      }
      `,
      {
        variables:
        {
          "name": "1000 imported orders.",
          "returnUrl": "http://super-duper.shopifyapps.com/",
          "price": {
            "amount": 10,
            "currencyCode": "USD"
          }
        }
      },
  );
  if (mutation != null){
    const muJson = await mutation.json();
    if (Array.isArray(muJson.data.appPurchaseOneTimeCreate.userErrors) && muJson.data.appPurchaseOneTimeCreate.userErrors.length >= 1){
      console.log("Error: ",muJson.data.appPurchaseOneTimeCreate.userErrors)
      return null;
    }
    // Redirect to checkout
    console.log("appPurchaseOneTime",muJson.data.appPurchaseOneTimeCreate.appPurchaseOneTime);
    console.log("ConfirmationUrl ", muJson.data.appPurchaseOneTimeCreate.confirmationUrl)
    throw redirect(muJson.data.appPurchaseOneTimeCreate.confirmationUrl, 303);
  }
  return null;
}

The real fun part is that i can take the redirect url from the 302 header sent, copy it into the browser bar, and it works. But the remix redirect function does not work with this url

1 Like

Same issue as well. Did you manage to find a fix or an alternative way to handle this?

try

redirect(confirmationUrl, { target: "_parent" })

?

2 Likes

You made my day sir!

It’s working finally

The only way that I have been able to come up with is to open in a separate window:

export async function action({ request, params }) {
  
    const { admin, session } = await authenticate.admin(request);
    const { shop } = session;
  
   let res = await createShopSubscription("Basic", admin.graphql);

   console.log(res.data.appSubscriptionCreate.confirmationUrl);
        
    // -ignore
    return {confirmationUrl: res.data.appSubscriptionCreate.confirmationUrl};
  }

  
  export default function Billing() {

    const navigate = useNavigate();
    const submit = useSubmit();

    const data = useActionData();

    if(data.confirmationUrl){
        window.open(data.confirmationUrl, "_blank")
    }
// .........

Did you try the suggestion I posted above? Seems to work.

Not working for me, I get

**Object literal may only specify known properties, and ‘target’ does not exist in type ‘ResponseInit’.**ts(2353)

I’m using redirect from remix-node:
import {redirect} from “@remix-run/node”****;

Is there a different import I should be using?

update:

of course I get it working right after posting lol

If anyone else hits this particular issue, don’t use the redirect import from remix-run/node.
Instead, do authenticate and get the redirect object from that, e.g:

export async function action({ request }) {
    const {session, admin, redirect} = await authenticate.admin(request);

    // code for billing/subscription

    return redirect(response.confirmationUrl, { target: "_parent" });
}
4 Likes

sadly, still not work to me. it redirect me to a blank page. does anyone have same issues?

This worked for me! Thanks!

this not works on me,

I dont have a choice but to return the confirmationUrl to client then is the window is available I can use window.open() in new page,

I cant use redirect to fully redirect the page in confirmationUrl.

is there anyone found a solution for this issue?