#shashan_94612
1 messages · Page 1 of 1 (latest)
If you click into that line, what do you see? Any Id to share? sub_xxx for a SubscripionId
@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.
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?
This step https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=elements#collect-payment
@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;
You are fetching from ${API_URL}/payment
You want ${API_URL}/create-subscription instead
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?
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
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 ?
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
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?
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
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 ?
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
Hey, taking over here. Let me know if there's any follow-up Qs I can answer!
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 ?
Can you summarise. the actual error/issue for me?
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
Why are you creating a Subscription and a Payment Intent?
The Subscription will generate a Payment Intent for you, if required
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