how can I got stripe confirmation after successfully paid a payment? - stripe-payments

I am trying to console after getting my payment but it doesn't work.
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
// Make sure to change this to your payment completion page
return_url: "/dashBoard/myorder",
},
},

From the Stripe.js website:
stripe.confirmPayment({
elements,
confirmParams: {
// Return URL where the customer should be redirected after the PaymentIntent is confirmed.
return_url: 'https://example.com',
},
})
.then(function(result) {
if (result.paymentIntent) {
}
});

Related

How do I know which user has made the payment in stripe

I am integrating stripe with my application. I want to receive a one time payment from a logged in user and once the payment is done maybe save the payment status in the database.
I have set up the stripe-checkout and stripe-webhook. But how would i know which logged in user from the client side has made the payment so that i can set the payment status for that user in the database.
Here is how my checkout and webhook look like.
app.post("/checkout-session", async (req, res) => {
try {
const session = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
mode: "payment",
line_items: req.body.items.map((item) => {
const storeItem = storeItems.get(item.id);
return {
price_data: {
currency: "usd",
product_data: {
name: storeItem.name,
},
unit_amount: storeItem.priceInCents,
},
quantity: item.quantity,
};
}),
success_url: `${process.env.CLIENT_URL}/success`,
cancel_url: `${process.env.CLIENT_URL}/failure`,
});
res.json({ url: session.url });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
let event;
// Only verify the event if you have an endpoint secret defined.
// Otherwise use the basic event deserialized with JSON.parse
if (process.env.STRIPE_WEBHOOK_SECRET) {
// Get the signature sent by Stripe
const signature = req.headers["stripe-signature"];
try {
event = stripe.webhooks.constructEvent(
req.body,
signature,
process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
console.log(`⚠️ Webhook signature verification failed.`, err.message);
return res.sendStatus(400);
}
}
// Handle the event
switch (event.type) {
case "payment_intent.succeeded":
const paymentIntent = event.data.object;
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`);
console.log(paymentIntent);
// Then define and call a methstripe loginod to handle the successful payment intent.
// handlePaymentIntentSucceeded(paymentIntent);
break;
case "payment_method.attached":
const paymentMethod = event.data.object;
// Then define and call a method to handle the successful attachment of a PaymentMethod.
// handlePaymentMethodAttached(paymentMethod);
break;
case "payment_intent.payment_failed":
const failedpaymentIntent = event.data.object;
console.log(`PaymentIntent for ${paymentIntent.amount} failed!`);
// Then define and call a methstripe loginod to handle the successful payment intent.
// handlePaymentIntentSucceeded(paymentIntent);
break;
case "checkout.session.completed":
console.log(event.data.object);
// console.log(`PaymentIntent for ${paymentIntent.amount} failed!`);
// Then define and call a methstripe loginod to handle the successful payment intent.
// handlePaymentIntentSucceeded(paymentIntent);
break;
default:
// Unexpected event type
console.log(`Unhandled event type ${event.type}.`);
}
// Return a 200 response to acknowledge receipt of the event
res.send();
});```
In checkout.session.completed event, you will be able to find customer_details.email in the Checkout Session object to identify the customer.
Alternatively, your internal customer ID might be set under metadata parameter in Checkout Session Creation API. Metadata will be present in checkout.session.completed after successful payment which you can use to update the payment status in your database.
At the login time, you can use json web token (jwt) to send logged in user object in encrypted format and use local storage to store that token. and with request, send this token to backend and decode it. You will get user object from that and then you can able to find which user is sending request.
https://www.npmjs.com/package/jsonwebtoken

Stripe subscription always gives me "status: 'requires_confirmation'

I have a subscription route like this. My flow looks like this
User select a plan.
User enter card details through Stripe Card Element
User click Subscribe button.
As per docs,
I'm creating a customer.
Then creating a subscription for this customer.
But, my dashboard says payment incomplete and response object on creating subscriptions shows status: 'requires_confirmation'. What I am doing wrong?
router.post('/subscription', auth, async (req, res) => {
const { payment_method, price_id } = req.body;
const customer = await Stripe.customers.create({
email: 'test#gmail.com',
payment_method: payment_method,
description: 'New Customer',
invoice_settings: { default_payment_method: payment_method }
});
try {
const subscription = await Stripe.subscriptions.create({
customer: customer.id,
items: [
{
price: price_id
}
],
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent']
});
res.send({
status: subscription.latest_invoice.payment_intent.status,
subscriptionId: subscription.id,
});
} catch (error) {
return res.status(400).send({ error: { message: error.message } });
}
});
[![Stripe dashboard][1]][1]
[1]: https://i.stack.imgur.com/Sx0zN.png
It sounds like you’re doing things a bit out of order from the way the Stripe docs suggest. In this guide, the subscription object is created prior to collecting the payment method. The reason your invoice isn’t automatically paid is because you are explicitly passing in a payment_behavior of default_incomplete, which tells Stripe not to pay the invoice and allows you to collect payment details client-side and confirm the payment. Since you have already collected payment details, don’t pass in a payment_bevavior of default_incomplete.

How to access clientReferenceId on success using Stripe Checkout

I'm new to Stripe and using what appears to be a very simplistic setup to accept payments using Stripe Checkout. I'm passing a clientReferenceId which I need to access on the success page. Is this possible? Here's the code which is called on the Checkout button:
const stripeCheckout = async () => {
setLoading(true)
const stripe = await stripePromise;
const { error } = await stripe.redirectToCheckout({
lineItems: [
{
price: 'price_xxxxx',
quantity:1,
}
],
mode:"payment",
cancelUrl: window.location.origin,
successUrl: `${window.location.origin}/payment-complete`,
clientReferenceId: 'abc',
});
if (error) {
console.log("Error # Checkout: ",error)
setLoading(false)
}
}
Thank you for any help.
You can access the client_reference_id by retrieving the Checkout Session on the success page: https://stripe.com/docs/payments/checkout/custom-success-page
However a much easier solution would be to just encode your variable directly into the success URL:
successURL: `${window.location.origin}/payment-complete?id=abc`,
Then on your success page you can just access the query string variables.

Stripe "Missing required param: line_items[0][currency]." Node js

I'm creating subscription on node js backend. It had been working good but today I got this error. I didn't made any changes in code - it just starts returning this error.
backend code:
app.post('/api/subscription', async (req, res) => {
const { priceId } = req.body;
try {
const session = await stripe.checkout.sessions.create({
mode: "subscription",
payment_method_types: ["card"],
line_items: [
{
price: priceId,
// For metered billing, do not pass quantity
quantity: 1,
},
],
// {CHECKOUT_SESSION_ID} is a string literal; do not change it!
// the actual Session ID is returned in the query parameter when your customer
// is redirected to the success page.
success_url: 'https://someurl',
cancel_url: 'https://someurl',
});
res.send({
sessionId: session.id,
});
} catch (e) {
console.log(e)
res.status(400);
return res.send({
error: {
message: e.message,
}
});
}
})
from client I'm sending
fetch("http://localhost:8000/api/subscription", {
method: "POST",
body: JSON.stringify({ priceId }),
});
I've taken this code from official stripe example here https://stripe.com/docs/billing/subscriptions/checkout
And as I said it works fine, and now I've tested it on two different stripe accounts and getting the same error. It looks like something changed on stripe but not in their documentation
If priceId is undefined/null it won't be sent in the request. If the Price isn't present the API assumes you're trying to specify information about a line item without using a Price, and one of the first checks it performs is for a valid currency (which you don't have), which results in the Missing required param: line_items[0][currency]. error.
To fix the issue you'll need to figure out why priceId isn't being populated as expected, and you may also want to add a check to make sure priceId is valid before proceeding to the Checkout Session creation step.

Why are the Stripe Payments Incomplete?

My Stripe payments show up on my dashboard, but they have an 'Incomplete' status, and hovering over shows the tip, "The customer has not entered their payment method." I thought I accounted for payment method in my sessions.create() method.
My Angular component creates a StripeCheckout and sends the session data to my API. API then includes it in the response to the browser (my first attempt was to use this sessionId to redirect to checkout, but I chose this because it was smoother).
Angular/TS StripeCheckout and handler:
let headers = new Headers();
headers.append("Content-Type", "application/json");
headers.append(
"authentication",
`Bearer ${this.authServ.getAuthenticatedUserToken()}`
);
this.handler = StripeCheckout.configure({
key: environment.stripe_public_key,
locale: "auto",
source: async source => {
this.isLoading = true;
this.amount = this.amount * 100;
this.sessionURL = `${this.stringValServ.getCheckoutSessionStripeURL}/${this.activeUser.id}/${this.amount}`;
const session = this.http
.get(this.sessionURL, {
headers: new HttpHeaders({
"Content-Type": "application/json",
authentication: `Bearer ${this.authServ.getAuthenticatedUserToken()}`
})
})
.subscribe(res => {
console.log(res);
});
}
});
//so that the charge is depicted correctly on the front end
this.amount = this.amount / 100;
}
async checkout(e) {
this.stripeAmountEvent.emit(this.amount);
this.handler.open({
name: "[REDACTED]",
amount: this.amount * 100,
description: this.description,
email: this.activeUser.email
});
e.preventDefault();
}
NodeJS API picks it up
exports.getCheckoutSession = catchAsync(async (req, res, next) => {
const currentUserId = req.params.userId;
const paymentAmount = req.params.amount;
const user = await User.findById(currentUserId);
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
success_url: `${process.env.CLIENT_URL}`,
cancel_url: `${process.env.CLIENT_URL}`,
customer_email: user.email,
client_reference_id: user.userId,
line_items: [
{
name: `Donation from ${user.userName}`,
description: '[REDACTED]',
amount: paymentAmount,
currency: 'usd',
quantity: 1,
customer: user.userId
}
]
});
const newPayment = await Payment.create({
amount: paymentAmount,
createdAt: Date.now(),
createdById: user._id
});
res.status(200).send({
status: 'success',
session
});
});
The payment gets created in my db, and the payment shows up on my Stripe dashboard. The payments show as 'Incomplete' when I expected it to charge the card.
Thanks in advance.
The latest version of Checkout lets you accept payments directly on a Stripe-hosted payment page. This includes collecting card details, showing what's in your cart and ensuring the customer pays before being redirected to your website.
At the moment, though, your code is mixing multiple products in one place incorrectly. The code you have client-side uses Legacy Checkout. This is an older version of Stripe's product that you could use to collect card details securely. This is not something you should use anymore.
Then server-side, you are using the newer version of Checkout by creating a Session. This part is correct but you never seem to be using it.
Instead, you need to create the Session server-side, and then client-side you only need to redirect to Stripe using redirectToCheckout as documented here.

Resources