#shashan_94612

1 messages · Page 1 of 1 (latest)

quaint waveBOT
waxen mesa
#

If you click into that line, what do you see? Any Id to share? sub_xxx for a SubscripionId

pale pine
#

@waxen mesa I'm not sure what you mean, in the backend, it's clear the customer is subscribed and has an invoice, please let me know if you mean something different.

waxen mesa
#

Okie so this is a Subscription created, but looks like you haven't confirmed its PaymentIntent

#

Did you run the frontend logic to confirm its PaymentIntent?

pale pine
#

@waxen mesa I'm using React Native (Expo), is there any document how to confirm payment intent ?this is my code for payment

import { useState } from "react";
import { Alert, View } from "react-native";
import InvoiceBtn from "../general/Button";
import { useStripe } from "@stripe/stripe-react-native";

const PaySubscription = ({route}) => {
  const {customerId, itemId, amount, subscriptionId, clientSecret} = route.params;
  const [loading, setLoading] = useState(false);
  const API_URL = "https://ray-mobile-backend.onrender.com";
  const stripe = useStripe();

  const payHandler = async() => {
    setLoading(true)
    try {
      // sending request
      const response = await fetch(`${API_URL}/payment`, {
        method: "POST",
        body: JSON.stringify({ amount, customerId }),
        headers: {
          "Content-Type": "application/json",
        },
      });
      const data = await response.json();
      
      if (!response.ok) return Alert.alert(data);
      const clientSecret = data.clientSecret;
      setLoading(false)
      const initSheet = await stripe.initPaymentSheet({
        paymentIntentClientSecret: clientSecret,
      });
      if (initSheet.error) return Alert.alert(initSheet.error.message);
      const presentSheet = await stripe.presentPaymentSheet({
        clientSecret,
      });
      if (presentSheet.error) return Alert.alert(presentSheet.error.message);
      Alert.alert("Payment complete, thank you!");
    } catch (err) {
      console.error(err);
      Alert.alert("Something went wrong, try again later!");
    }
  }

  return (
    <View className="py-12 px-4 flex justify-center bg-white">
      <InvoiceBtn text="Pay" duty={payHandler} />
    </View>
  );
}

export default PaySubscription;
waxen mesa
#

You are fetching from ${API_URL}/payment

#

You want ${API_URL}/create-subscription instead

pale pine
#

Wait you mean the subscription and payment should go together ? it should be one client secret? as of now subscription make a client secret and payment creates another, so both should be the same?

waxen mesa
#

They are 2 different endpoints and will generate 2 different payment intents, hence 2 different client secrets. Since you are working with Subscription, you should call the create-subscription endpoint

pale pine
#

So, I just have to merge and run those two functions together in the backend? and unify the logic in the frontend, basically those two should not be two different operations (subscription, payment) rather one operation done consequently ?

waxen mesa
#

They are 2 endpoints, so you don't need to merge and run together. Each endpoint could be called separately.

#

It's up to you to remove the payment one if you don't use it

pale pine
#

Sorry, I'm new to this, for this to appear as if it's a payment for the subscription, it has to have the same clientSecret or what? I'm trying hard to get my head around it, at first, I thought only customerId is enough, but it seems it's not enough right?

waxen mesa
#
    res.send({
      subscriptionId: subscription.id,
      clientSecret: subscription.latest_invoice.payment_intent.client_secret,
    });

Each request to your create-subscription will returns a different clientSecret from here

#

It's not the same with anywhere

#

each clientSecret you can supply to your ReactNative, and it will try to confirm the PaymentIntent

pale pine
#

so I have to basically provide the clientSecret returned from subscription to the payment instead of waiting for the payment to create its own intent ?

waxen mesa
#

app.post('/create-subscription', async (req, res) => {
vs
app.post("/payment", async (req, res) => {
are 2 different endpoints. They don't run at the same time, only one at a time. So they are not related to each other at all

quaint waveBOT
lapis beacon
#

Hey, taking over here. Let me know if there's any follow-up Qs I can answer!

pale pine
#

Thanks @lapis beacon I made the function together in the backend, and in the frontend (as shown) I still get the same result, although I only send the paymentIntent once, (I guess), it's still incomplete, let me know if you have an idea why? Thanks for your time and help.

app.post('/create-subscription', async (req, res) => {
  const {customerId, priceId, amount} = req.body.
  try {
    const subscription = await stripe.subscriptions.create({
      customer: customerId,
      items: [{
        price: priceId,
      }],
      payment_behavior: 'default_incomplete',
      payment_settings: { save_default_payment_method: 'on_subscription' },
      expand: ['latest_invoice.payment_intent'],
    });
    const paymentIntent = await stripe.paymentIntents.create({
      amount:amount,
      currency: "CAD",
      automatic_payment_methods: {
        enabled: true
      },
      metadata: {},
    });
    const clientSecret = paymentIntent.client_secret;
    res.json({ message: "Payment", clientSecret, subscriptionId: subscription.id });
  } catch (error) {
    ..error
  }
});

#Frontend

  const subscribe = async(item) => {
    const itemId = item.id;
    const amount = item.unit_amount;
    const response = await fetch(`${API_URL}/create-subscription`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        priceId: `${itemId}`,
        customerId: `${customer}`,
        amount: `${amount}`
      }),
    })
    const data = await response.json()
    if (!response.ok) return;
    const clientSecret = data.clientSecret;
    const initSheet = await stripe.initPaymentSheet({
      paymentIntentClientSecret: clientSecret,
    });
    if (initSheet.error) return Alert.alert(initSheet.error.message);
    const presentSheet = await stripe.presentPaymentSheet({
      clientSecret,
    });
    if (presentSheet.error) ...error
    Alert.alert("Payment complete, thank you!");
  }
#

@lapis beacon how to tell the payment intent to work with the subscription ?

lapis beacon
#

Can you summarise. the actual error/issue for me?

pale pine
#

I have some users (React Native) who register, subscribe to Stripe, then their status is incomplete, I want to make the first payment so their status would change to complete, but I fail. It's a recurring subscription and it should work but the first payment somehow is not related to the subscription

lapis beacon
#

Why are you creating a Subscription and a Payment Intent?

#

The Subscription will generate a Payment Intent for you, if required

pale pine
#

Yes but the documentation says the intent should be incomplete when doing subscription and when you make your first payment (paymentIntent), it will be comeplete, I don't know how to reconcile these two together now, I'm using Expo (React Native), so there are some hurdles. But let me know if you have an idea? should i change the intent from subscription or how to make the payment through the subscription directly? @lapis beacon