#rtx_checkout-paymentintent

1 messages ยท Page 1 of 1 (latest)

frail yarrowBOT
#

๐Ÿ‘‹ Welcome to your new thread!

โฑ๏ธ We automatically close idle threads, which makes them read-only. Make sure you stick around to chat in realtime!

๐Ÿ”— This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1212089153601413152

๐Ÿ“ Have more to share? You can add more detail below, including code, screenshots, videos, etc.

โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question. Thank you for your patience!

cobalt valeBOT
lethal raft
#

@fluid marsh that is expected. The PaymentIntent is not created immediately. It will only be created once the customer is trying to pay on Checkout. This limits the number of "incomplete payments" you would see in the Dashboard.

#

rtx_checkout-paymentintent

fluid marsh
lethal raft
#

you would "link" the PaymentIntent and the Checkout Session after it was completed successfully

fluid marsh
#

Why aren't these linked automatically tho?

lethal raft
#

They are linked automatically tho.

#

You create a Checkout Session. There is no PaymentIntent created yet. Later when the customer goes on Checkout and pays, a PaymentIntent gets created. At that point the Checkout Session would have payment_intent: 'pi_123' set as expected.

#

But really you don't need to "link" this until after the payment completes successfully and you go through order fullfiment as covered in the doc I shared above. And at that point you can do the reconciliation in your database.

fluid marsh
fluid marsh
lethal raft
#

I'm sorry I don't really follow you. The doc I linked supports all languages, you can switch it to pick the one you want.
I also don't really understand what you mean with the first reply. Can you try and be a lot more specific about the exact issue? In theory you would get checkout.session.completed on your WebhookEndpoint and that will have all the information you need

fluid marsh
#

Oh so that's a webhook I have to listen to?

#

I didn't know I could change the language, my bad!

lethal raft
#

yeah we changed the layout for code. I think it's less "obvious" I'll share the feedback

fluid marsh
#

No no i'm just stupid ๐Ÿ˜„ My lazy eyes didn't see it

lethal raft
#

haha you're not the first one to say this. In the past we had "tabs" for each language and it was a lot more obvious (and you could cmd+F for your language)

fluid marsh
#

I first had this but I guess this isn't exactly the proper way haha

// Node.js example using Express
const express = require("express");
if (process.env.NODE_ENV !== 'production') {
  require('dotenv').config();
}

const cors = require("cors");
const app = express();
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);
app.use(express.json());
app.use(cors({ origin: process.env.CORS_ORIGIN }));

// Endpoint to create a checkout session
app.post("/create-checkout-session", async (req, res) => {
  const { products } = req.body;

  try {
    const session = await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      line_items: products,
      mode: "payment",
      success_url: `${process.env.FRONTEND_URL}/checkout/success?session_id={CHECKOUT_SESSION_ID}`,
      cancel_url: `${process.env.FRONTEND_URL}/cart`,
      payment_intent_data: {
        statement_descriptor: process.env.STATEMENT_DESCRIPTOR,
      },
    });

    res.json({ sessionId: session.id, status: "success" });
  } catch (error) {
    res.status(500).send(error.toString());
  }
});

// Endpoint to retrieve the checkout session and get the payment_intent
app.get("/retrieve-checkout-session/:sessionId", async (req, res) => {
  const { sessionId } = req.params;

  try {
    const session = await stripe.checkout.sessions.retrieve(sessionId);

    // Check if payment_intent is available
    if (session.payment_intent) {
      res.json({ paymentIntentId: session.payment_intent });
    } else {
      res.status(404).send("Payment Intent not found for the given session.");
    }
  } catch (error) {
    res.status(500).send(error.toString());
  }
});

app.listen(process.env.PORT, process.env.HOST, () => console.log(`Running on port ${process.env.PORT}`));

lethal raft
#

your success URL is ${process.env.FRONTEND_URL}/checkout/success?session_id={CHECKOUT_SESSION_ID} so after Checkout completes when the customer pays they would end up on /checkout/success so you need a route for this

fluid marsh
#

I have a route for that, but that's also another question I have.

Is CHECKOUT_SESSION_ID automatically replaced with the value?

lethal raft
#

yes

#

you can try this end to end in Test mode to confirm quickly!

fluid marsh
#

Already in test mode. Had to learn that the hard way when I accidentally actually paid for something non existent haha

lethal raft
#

lol

fluid marsh
#

I will let you know as soon as possible if it works

lethal raft
#

sounds good!

fluid marsh
#

So the first part works haha now gotta do the payment intent stuff

lethal raft
#

yay!

frail yarrowBOT
fluid marsh
stiff kraken
#

Hello! I'm taking over and catching up...

fluid marsh
#

Hey!

stiff kraken
#

You shouldn't rely on the success page ever being reached. Someone can pay successfully in Checkout, then drop off before they get redirected to your success page. What we recommend is that you have both webhooks and the success page trigger fulfillment, with a first-one-to-do-it-wins approach.

#

So, if you get a checkout.session.completed Event first (or only) use that to trigger fulfillment. If someone lands on the success page first, before you get that Event, you can trigger fulfillment immediately and then when the Event does come in you can ignore it since fulfillment already happened.

fluid marsh
#

Alright thanks. Let me try that! I will notify you if this works

#

Does the webhook itself have a different secret?

stiff kraken
#

Each Webhook Endpoint has a different webhook signing secret, yeah.

fluid marsh
#

I mean like an API token

#

API secret or whatever you want to call it haha

stiff kraken
#

Sorry, I'm not sure what you're referring to. Why are you asking? Are you running into an issue?

fluid marsh
#

Yeah I'm kinda stuck here.
What endpoint URL should I even put there? My localhost:3000/webhook ?

#

Stripe is never going to be able to reach localhost? xD

stiff kraken
#

If you're testing locally you need to use Stripe CLI to forward Events to your local web server. Webhook Endpoints you set up in the Dashboard only work with URLs that are live and reachable online.

fluid marsh
#

Hmm mkay. Is there a different way I can do this without having to use Webhooks?

#

I feel like if I have to do so much effort just to get the Payment Intent Id, it's not really worth getting it this way?

#

I don't want to sound lazy ๐Ÿ˜ but this sounds like a lot of setting up to do for just an id

stiff kraken
fluid marsh
#

Alrighty. So i just tested it with the CLI and the event was successful.
Sounds like Il have to put in my production URL in then if I want it to work without cli

stiff kraken
#

Yep. Stripe CLI is for testing locally, the Webhook Endpoints are for live URLs that are reachable online.

fluid marsh
#

I will try to figure that out tommorow!

#

Thanks for the help so far!