Stripe - how to list active and trialing subscriptions together - node.js

I am using NodeJs with Stripe. I want to retrieve all active and trialing subscriptions of one customer in a nice way. So far I was only able to retrieve subscriptions separately.
const activeSubscriptionsObject = await stripe.subscriptions.list({
customer: customerId,
status: 'active'
});
const trialingSubscriptionsObject = await stripe.subscriptions.list({
customer: customerId,
status: 'trialing'
});
What should I do to get a subscription object that contains both trialing and active subscriptions?

You cannot retrieve two explicit status (and not others) like you've asked. The way to do this is either:
As you've done, retrieve active and trialing separately then merge the results; or,
Request the list with status=all to get everything (API ref), then filter the results yourself.
Like so:
const allSubs = await stripe.subscriptions.list({
customer: customerId,
status: 'all'
});
const statuses = ['active', 'trialing'];
const trialAndActiveSubs = allSubs.data.filter(sub => statuses.includes(sub.status));

Related

Stripe discount on upcoming payment of recurring subscription

I have implemented stripe recurring subscription that billed annually. I've proposed an offer for my customers that if they refer our website to 5 of their friends and they register, they will get 50% off on their subscription.
How I'll implement that discount for that particular customer on next payment?
The simplest option would be to apply a Coupon to the customer’s subscription. Then during the next billing cycle of the subscription, the coupon will be automatically applied. That can be done is two steps (here done node.js):
// Create the new Coupon, once
// Doc: https://stripe.com/docs/api/coupons/create
const coupon = await stripe.coupons.create({
percent_off: 50,
duration: 'once', // other possible value are 'forever' or 'repeating'
});
// Then every time a customer match your criteria, update their subscription
// Doc: https://stripe.com/docs/api/subscriptions/update
const subscription = await stripe.subscriptions.update(
'sub_xxx',
{ coupon: coupon.id }
);
Another option would be to apply the coupon to the customer instead of on the subscription directly. In that case the coupon would apply to all recurring charges for that customer.
// Doc: https://stripe.com/docs/api/customers/update
const customer = await stripe.customers.update(
'cus_xxx',
{ coupon: coupon.id }
);

Once off payment with Stripe using the API ID

I have created a subscription service using Stripe. I can subscribe a user to use recurring payments. This is the relevant code (node):
// Create the subscription
const subscription = await stripe.subscriptions.create({
customer: req.body.customerId,
items: [{ price: req.body.priceId }],
expand: ['latest_invoice.payment_intent'],
});
This works and uses the priceId as shown in the dashboard:
However, it falls over when I sell a product which isn't recurring. I get the error:
The price specified is set to `type=one_time` but this field only accepts prices with `type=recurring`
I understand the error, but I am not sure if I can set a subscription to not be recurring.
My app has 3 tiers:
once off
monthly
yearly
Ideally, I would like not to add a whole new section of code to handle what seems like a subset of what subscriptions do, but even if I do, the paymentIntent object seems to only take an amount rather than the API ID as shown in the picture. Is there any way to do this using the infrastructure I have already built?
You can't create a subscription with a non-recurring price, instead for one-off payments you'd use a PaymentIntent.
Prices are meant for use with subscriptions and the Checkout product, but you can still use the data in them for PaymentIntents. For instance:
// get the price
const price = await stripe.prices.retrieve(req.body.priceId);
// check if the price is recurring or not
if (price.recurring !== null) {
// Create the subscription
const subscription = await stripe.subscriptions.create({
customer: req.body.customerId,
items: [{ price: req.body.priceId }],
expand: ['latest_invoice.payment_intent'],
});
// do something with the subscription
} else {
const pi = await stripe.paymentIntents.create({
customer: req.body.customerId,
currency: 'usd',
amount: price.unit_amount,
});
// do something with the PaymentIntent
}
you can also attach one-time items via the subscription.create call by placing them in add_invoice_items.
see: https://stripe.com/docs/api/subscriptions/create?lang=node#create_subscription-add_invoice_items

Stripe get product_id / price_id from session object

I'm currently using Stripe Webhooks to get notified when user pays for a product. This is working fine. From the payment intent I can get the Seesion and the Customer Object. But I don't find a way to get the product_id or price_id for what the user paid.
Does someone know a way to get product_id or price_id ?
Thanks for the question. As you noticed the Session data included in the checkout.session.completed event does not include the line_items where the Price ID is associated to the Checkout Session.
line_items is one of the expandable properties, so to retrieve the Price ID you'd retrieve the Checkout Session and use expand to include the line items in the response. There is not a way to configure your webhook to have the data sent to you include this data.
There are two approaches to associating a customer's purchase with a Checkout Session. First, you could store the ID of the Checkout Session in your database alongside the cart or list of items purchased by the customer. That way you if a checkout session is successful, you can look up the cart by ID and know which items were purchased.
Alternatively you could listen for the checkout.session.completed webhook event, then when you receive a new notification for a successful checkout, retrieve the Session with expand then use the related price data.
Using stripe-node that would look like the following:
const session = await stripe.checkout.sessions.retrieve(
'cs_test_xxx', {
expand: ['line_items'],
},
);
// note there may be more than one line item, but this is how you access the price ID.
console.log(session.line_items.data[0].price.id);
// the product ID is accessible on the Price object.
console.log(session.line_items.data[0].price.product);
To take this a step further, if you wanted more than just the ID of the product, you could also expand that by passing line_items.data.price.product which would include the line items their related prices and the full product objects for those prices.
While creating the Payment Intent, you can store additional information about the object in the metadata field.
const paymentIntent = await stripe.paymentIntents.create({
amount: 1099,
currency: 'usd',
payment_method_types: ['card'],
metadata: {
product_id: '123',
price_id: '20',
},
});
Once the payment is done, you can retrieve this information from the metadata field.
You can do the same for the Session Object as well.
cjav_dev answer is great! Here is the PHP code for the same.
$event = \Stripe\Event::constructFrom(
json_decode($payload, true), $sig_header, $endpoint_secret
);
$eventObject = $event->data->object;
$stripe = new StripeClient('testsk_ssdfd...sdfs');
$csr = $stripe->checkout->sessions->retrieve($eventObject->id,
['expand' => ['line_items']]
);
$priceid = $csr->line_items['data'][0]['price']['id'];
Note the above is only retrieving the 1st line item. You may have to do a loop for all items.

How to query all active / online users?

According to the documentation, it seems that one needs to indicate the users list that we want to query e.g.:
const response = await client.queryUsers({ id: { $in: ['john', 'jack', 'jessie'] } });
In this example, we need to indicate that we want the details of these 3 users. Is there a way to query all active users instead of passing an array of ids / names?
I tried:
const response = await client.queryUsers(
{ presence: true },
);
But it returned an empty string.
presence: true registers your client to presence events (online/offline).
There is no support to get this in one go. Also, beware if user is hidden, the user is requesting this information might not be able to see the real online users.
Current recommendation is to get channel with state: true and iterate your members and also setting presence: true, you will be notified by status changes.

Stripe does not let a charge be associated with a customer with one-time source

As the title says, I am trying to make a payment using a one-time source (credit card) that is not being saved in the customer's profile. I still want to be able to record that charge on the customer's profile on Stripe.
According to the docs, this can be done by passing the customer's id in customer key in the payload sent to Stripe.customers.createCharge. However, on doing that, I receive an error stating the card is not linked with the customer (which obviously is not, and I don't want it to be).
Customer cus_*** does not have card with ID tok_visa
To get around this, temporarily I have applied the fix mentioned in this answer which basically involves creating a temporary card for the payment and then deleting it.
I was wondering how does the API not work when it is clearly documented otherwise, hope someone experienced with Stripe chimes in on the same.
Here is the code I'm trying to get to run:
await stripeService.charges.create({
source: token, // temporary token received from Checkout
customer: user.stripeCustomerId, // the Stripe customer ID from my database
amount,
currency: 'usd',
description: 'Test charge'
});
The single-use sources document that you link to explicitly only works with Sources, but tok_visa will create a Card object instead. I believe that's why you get the error.
If you try the code with a Source(it has an ID like 'src_xxx') that you obtain through Elements/Checkout on your frontend with, for example, createSource, it will succeed, I've just tested it. You can also test with this code :
const src = await stripe.sources.create({
type : "card",
token : "tok_visa"
});
const charge = await stripe.charges.create({
    source : src.id,
customer : "cus_xxxx",
    amount : 1000,
    currency : "usd"
});
I was able to achieve this by creating the source first followed by the charge where you specify the customerId and sourceId as below:
//Create the source first
var options = new SourceCreateOptions
{
Type = SourceType.Card,
Card = new CreditCardOptions
{
Number = Number,
ExpYear = ExpYear,
ExpMonth = ExpMonth,
Cvc = Cvc
},
Currency = "gbp"
};
var serviceSource = new SourceService();
Source source = serviceSource.Create(options);
//Now do the payment
var optionsCharge = new ChargeCreateOptions
{
Amount = 500,
Currency = "gbp",
Description = "Your description",
SourceId = source.Id,
CustomerId = "yourcustomerid"
};
var service = new ChargeService();
service.Create(optionsCharge);
result = "success";

Resources