Get purchased product from PaymentIntent - stripe-payments

in my app i want to list past purchases for a stripe customer. So I was looking at the relevant API objects like PaymentIntents, Sessions or Charges. But they all do not seem to contain any reference to Product or Price, which I would need to list the purchased products.
Subscriptions contain a list of items that are contained in that subscription, so I was expecting PaymentIntents to have something like that too.
Does anyone has an idea how to archive my list of past purchases? Thanks!

I did some digging through the Stripe API docs[1] and, out of the three objects you referrenced (PaymentIntent, Session, Charges), the only one that I can see being able to trace back to a product is the Session.
Session objects have a line_items property[2] which can be followed all the way down to line_items.data.price.product[3]. To access this you’ll need to inlcude the expand=["data.line_items"] parameter to your call to list Checkout Sessions. You can read more about expanding API responses here[4]
So for all the charges to your customers that were done using Checkout Sessions, you could list them all, use the customer property to associate earch session with a customer in your application, traverse the the returned data, and then query the API for the product details. If you have a lot of customers & products these API calls will add up fast so I would store this data in your back-end to avoid hitting rate limits[5].
Alternatively, you could just save the product ID (either Stripe or your local version) as metadata[6] for any of the above Stripe payment objects listed. That would allow you to link any payment object you wish to a product.
https://stripe.com/docs/api
https://stripe.com/docs/api/checkout/sessions/object#checkout_session_object-line_items
https://stripe.com/docs/api/checkout/sessions/object#checkout_session_object-line_items-data-price-product
https://stripe.com/docs/expand
https://stripe.com/docs/rate-limits
https://stripe.com/docs/api/metadata

I had the same question I found a way to retrieve the products related to a specific PaymentIntent.
You need to get the sessions that was linked to PaymentIntent when the Checkout process was made.
I will give you the code (in PHP) that I use to to this.
\Stripe\Stripe::setApiKey(STRIPE_API_SECRET);
// Find the Session for that PaymentIntent
$sessions = \Stripe\Checkout\Session::all([
'payment_intent' => "pi_xxxxxxxxxx",
'expand' => ['data.line_items'],
]);
You will then have an key line_items that contain the products linked.
Enjoy

Related

Is it okay to have a bunch of incomplete Stripe payment intents?

I am implementing the Stripe payment platform using JavaScript and the PHP SDK.
I don't have any issues with the implementation itself, but I am not sure whether I have to reuse an existing PaymentIntent or it's perfectly fine to have a bunch of them created and incomplete.
I searched for this in Stripe's documentation, but I can't seem to find anything related to this.
For example, in my test account I have this:
It's all for the same transaction, because I was changing some visuals and refreshing the browser.
I am aware that each PaymentIntent has an ID, but is it recommended to add it as a query parameter and retrieve it on refreshing, or is it better to always generate a new Payment Intent.
My main reasoning is to avoid having a huge collection of incomplete payment intents.
The default integration path for Stripe today is to create a PaymentIntent first so that you get a client_secret you can use client-side to render their UI via PaymentElement. This means that if your customers decide not to pay after all, you end up with an incomplete PaymentIntent which is expected.
This is not really a problem, other than appearing in the Payments list which can be confusing. You could also write a background job daily that would cancel any PaymentIntent via you know won't be completed because the customer left and you didn't have any data to contact them to upsell them for example but this isn't really needed.
Stripe also has a beta (docs) right now (Feb 2023) that changes the default integration path. This simplifies the experience because you can render the PaymentElement client-side with specific options such as amount and currency. You'd then only create the PaymentIntent at the end of the flow
when the customer is attempting to pay. That flow limits the number of incomplete PaymentIntents since you only create them when the customer really pays. You'd still get some, for example after a decline by the customer's bank though.

How to use stripe checkout for first come, first served buying experience

I'm trying to use Stripe checkout in a first-come, first-served buying process. Multiple buyers may be trying to buy the same item at the same time, and only the one who completes the stripe checkout process first should get it. At the moment, the stripe checkout session duration requires me to 'book' the stock item and only release them back into stock once the session duration expires (even if they close the tab).
Is there a way to set up Stripe Checkout in a way that would detect whether the item has already been purchased by another buyer (e.g. the stock is no longer available), and for example show an error when the user tries to pay?
If not, any suggestions as to alternative ways of implementing this functionality while still using Stripe?
You can listen for checkout.session.completed events and add some event handler logic to retrieve the Session object while expanding the line_items:
https://stripe.com/docs/payments/checkout/fulfill-orders
https://stripe.com/docs/api/expanding_objects
This will allow you to inspect the price and product IDs for the completed Session. You could then have some logic to expire any other Checkout sessions so no other customers are able to go through the payment flow:
https://stripe.com/docs/payments/checkout/managing-limited-inventory
https://stripe.com/docs/api/checkout/sessions/expire
You can use the paymentIntent that allows you to confirm or reject the payment later. You can create the paymentIntent for all the customers are trying at the same time and next take the first one and confirm only this paymentIntent and reject the others
Read the Stripe documentation:
Stripe | PaymentIntent

Stripe: Get total successfully paid invoices count

I'm using stripe for subscription. Where i need to fire an event after 3 successfully charges.
For this i am using invoice.payment_succeeded webhook.
But there is no key which specify the number of this recurring payment means whether it is first or second or nth charge. So how could i get the number of successfully payment made on a subscription.
You can call the https://api.stripe.com/v1/invoices API endpoint with the customer's ID, the status parameter set to paid and optionally, the subscription parameter and then count how many invoices were returned.
There are some other parameters, like limit, starting_after, etc. that you can send it too.
The invoice.payment_succeeded webhook sends the invoice object in the data.object field so you should be able to get the customer and subscription values from it.
I'd recommend doing the invoices call asynchronously to ensure that the webhook call doesn't time out.
FYI there is an expand to it, like with the current node api;
const ret = await stripe.invoices.list(
{
expand: ["total_count"],
limit: 0,
});
console.log(ret.total_count)
It can be called with ${url}?expand[]=total_count&limit=0 too, if you need to write it by hand.
I did not found this in the documentation, but some libs using it, and it is indeed works. (But be careful, if it is not documented it could stop working too.)
Here is the docs; https://stripe.com/docs/api/pagination/search#search_pagination-total_count
Yes, as it is stated in the answer by D Malan, you can use the https://api.stripe.com/v1/invoices endpoint.
Though there is one thing to keep in mind when retrieving data from Stripe.
You can only get 100 items per call. Therefore, if you had recurring payment that generates more than 100 invoices after some time, you wouldn't be able to get the total count in one call. I suggest storing invoices/payment intents to your database and then using your DB engine to count the results.
Keep in mind that you should listen to invoice.payment_succeeded event in order to keep your database in sync, if you store the invoice or payment intent beforehand, while its status is not paid or succeeded, respectively.

Level 3 data with Stripe Payments

I'm working on a SAAS system that allows purchases to be made through a clients own payment gateway. We have one client that wants to use Stripe as their gateway, however as they are using Corporate Purchase Cards (CPC), it is necessary to pass Level 3 transaction details through. I've been trying to get details from Stripe on how we ensure that Level 3 data can be passed through successfully, however I'm not really getting anywhere with this in terms of getting any definitive information we can work with.
Stripe say that their system supports level 3 data, we just need to provide the data in the first place, however there is nothing in their documentation about this and the example we have been provided only allows for a single item to be listed - we will need to support a basket of different items.
We are using the Payment Intents process and already support adding in Metadata to the transaction. We've been told that adding metadata for SKU, Unit of Measure, Unit Price and Extended Price will allow level 3 processing, however this does seem to fall short of the information list on other sources (not to mention does not allow listing multiple items in the order due to the metadata keys needing to be unique)
Baed on that, our Metadata population looks like this (values hard coded to example purposes)
Dictionary<string, string> nRetVar = new Dictionary<string, string>();
nRetVar.Add("Customer", "John Smith");
nRetVar.Add("Email", "John.Smith#example.com");
nRetVar.Add("Order Number", "12345");
nRetVar.Add("Order Date", "2020-02-06");
nRetVar.Add("SKU", "ABCD1234");
nRetVar.Add("Unit of Measure", "1 Pack");
nRetVar.Add("Unit Price", "$10.00");
nRetVar.Add("Extended Price", "$15.00");
Stripe support never seem to directly answer any of the questions we have been asking about this, so it's proving very hard to get any progress on this - does anyone have enough experience with this to confirm if this metadata is enough to class as level 3, or is there more that we need to be adding?
Stripe supports Level 3 data in their API on both Charge and PaymentIntent. This feature though is currently "gated" which means you need to get access to the feature on your specific account. It's a bit similar to a long running beta. You should contact their support team again and ask for them to enable Level 3 data on PaymentIntent for your account.
The fields they are expecting as specific to that feature. This does not go inside metadata. The documentation is also gated which means you can only see it once you get access to the feature, to avoid confusion for other developers who don't have access.
You can see what the shape looks like in stripe-java for example on Charge here. The feature is not directly supported on PaymentIntent in the library though as this is still private.

how to add coupons to stripe's checkout

To enable SCA changes, I am now integrating https://stripe.com/docs/payments/checkout/client stripe's (stripe v3 js file) checkout feature to my app, which makes it easy for integration of my subscription system.
Question
how to pass coupons to stripe.redirectToCheckout() method, don't see anything related to this in documentation.
code sample
stripe.redirectToCheckout({
items: plans_and_addons,
successUrl: successUrl,
cancelUrl: cancelUrl,
clientReferenceId: customer_id, // helpful in webhook response
})
I am also facing the same issue so I contacted stripe support.
Please check the support team's reply.
I did a thorough research on your query and I'm afraid, Checkout supports only a limited set of customizations (e.g. name, description, logo) and fields. Focusing the UI allows us to iterate on it more effectively to improve conversions and maintain support across a wide range of platforms.
They provided me one document link you can also check it. https://stripe.com/docs/payments/checkout/customization
I think you can solve your problem by creating custom checkout with helping stipe API. --not tried.
As Daniel says above, you can't enable the promo codes when you call redirectToCheckout but you can enable the promo codes when you create the stripe session from your API.
So, to sum app, when you create the checkout session using Stripe.checkout.sessions.create() you have to also pass the allow_promotion_codes: true and this will actually allow you to apply promo codes to the products you have created in the stripe -> products page.
You can find more informations on this page: https://stripe.com/docs/billing/subscriptions/coupons/codes
I also ran into this, and what I've deduced from the Stripe docs is that you can't apply a coupon directly to the redirectToCheckout method, you have to create a Checkout session first and then use that.
Add a discount to Checkout the sample code is calling Checkout.session.create, not Checkout directly
redirectToCheckout Reference Docs doesn't mention a discount or coupon parameter at all, and the sample code again is creating a Checkout session using fetch (to one's own server backend, which is where my expertise ceases and where I'm stifled), to generate a session ID and then passing that into the result where redirectToCheckout is called.

Resources