Search code examples
stripe-paymentshttp-status-code-404fetch-apiendpointnext-intl

Fetch returns '404 Not Found' when calling a existing Stripe endpoint after I added next-intl


So to summarize : I'm currently doing a react/next e-shop, and using stripe for handling payments. Stripe provides checkout sessions that can be created in backend and will automatically redirect users on a payment form upon creation.

The thing to note is : I made it work pretty well on its own, but I have added a language feature on my app recently and suddendly my api endpoint handling this checkout can't be called, and returns a 404 not found error...

My api folder looks like this:

api
-> checkout
  -> route.ts
-> get-stripe-products
  -> route.ts
-> stripe-webhook
  -> route.ts

I call the checkout endpoint on a order page, using the following function that activates on a button click :

const checkout = async () => {
    await fetch("/api/checkout", {
      method: "POST",
      body: JSON.stringify({ products: cart }),
    })
      .then((response) => response.json())
      .then((response) => {
        if (response.url) {
          //response.url contain the success or failure url from transaction
          window.location.href = response.url;
        }
      });
};

now here's the weird part : trying to find the issue, I've played around with my endpoints, by calling each of them in this exact fetch, here are the responses I get in the network tab (F5 console) of my page :

-> fetch("api/checkout",...) :

Request URL: http://localhost:3000/api/checkout
Request Method: POST
Status Code: 404 Not Found

-> fetch("api/get-stripe-products,...) :

Request URL: http://localhost:3000/api/get-stripe-products
Request Method: POST
Status Code: 405 Method Not Allowed

(which is normal : get-stripe-product is a GET method, at least 405 indicates that the fetch found the file)

-> fetch("api/stripe-webhook,...) :

Request URL: http://localhost:3000/api/stripe-webhook
Request Method: POST
Status Code: 200 OK

I thought the issue might have been that the api folder wasn't found, but this shows otherwise...

So basically, I don't understand why it seems like my checkout endpoint can't be found by the fetch.

Again, on my app versions prior to adding languages handling (with next-intl), the same code snipet correcly initiates the stripe checkout session and I'm redirected to payment form without any issue.

Regarding code differences between my app versions :

  • the code snipet I've shown is the exact same between versions
  • the checkout/route.ts file has barely changed, I only modified the success_url and failure_url of the stripe.checkout.session object; if the error was from here I don't think it would return a 404 but a specific error. And it's not like the code inside the file is read since a 404 is thrown from the endpoint call

Any clue as to wth is causing this ?


Solution

  • Well found the issue faster than expected :

    A little more details about the language implementation I'm doing, since the problem was from here : With next-intl, all pages that need to exist in multiple languages have to be put in a [locale] folder, which adds an argument in url addresses (Ex: all pages that were in https://domain/page become https://domain/fr/page in my case)

    Correspondingly, I changed my success and failure url in my checkout endpoint that calls my checkout.session, since I needed to adapt the urls to the origin language :

    const session = await stripe.checkout.sessions.create({
    line_items: stripeItems,
    mode: "payment",
    shipping_address_collection: {
      allowed_countries: ["FR", "GB"]
    },
    success_url: `${pathOrigin}/${locale}/success`,
    cancel_url: `${pathOrigin}/${locale}/failure`
    

    })

    where the locale is initiated by the line :

    const locale = await getLocale()
    

    with getLocale being the backend function of next-intl to get the language parameter.

    Well, turns out you can't use that line in api endpoints... dunno how the issue exactly appears, but removing this line instantly solved my 404 not found.

    To still get my locale variable, I changed the body of my request on the order page, to include a locale parameter :

    const checkout = async () => {
    await fetch("/api/checkout", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ products: cart , locale}),
    })
    

    With locale being initiated by :

    const locale = useLocale();
    

    With useLocale being the front-end equivalent of getLocale.

    How I extract my request in api/checkout/route.ts :

      const { products, locale } = await request.json();
    

    That means the issue stems from next-intl... I'm curious about why the heck did that throw a 404 error but hey, hope nobody else spends 4 hours on this silly issue