How to retrieve Stripe subscription and credit card with one request only? - stripe-payments

in Stripe version 2020-03-02 I was able to retrieve a subscription and its associated credit_card in one go like this:
stripe_subscription = Stripe::Subscription.retrieve({:id => stripe_subscription_id, :expand => [:customer]})
stripe_customer = stripe_subscription.customer
stripe_credit_card = stripe_customer.sources.data.first
In version 2020-08-27 this seems no longer possible since Stripe won't recognise the sources attribute on customer.
So how can I retrieve a subscription and its credit card with one request only?

Since sources on Customer is not included by default, you have to explicitly include it when you expand the related properties. Your code would look like this:
stripe_subscription = Stripe::Subscription.retrieve({
id: stripe_subscription_id,
expand: ['customer.sources'],
})
stripe_customer = stripe_subscription.customer
stripe_credit_card = stripe_customer.sources.data.first
The expand feature is quite powerful and lets you expand multiple separate properties or chain expansion like we did above. I recommend reading the detailed documentation that Stripe shipped.

Related

stripe - find out which payment method did customer use

I'm using two different payment methods in my Stripe checkout, 'card' and 'sofort'.
For statistics purposes, I want to find out which payment method did my customer use after payment succeeded.
I had a look at the session I get back after checkout. But I couldn't find any useful information.
Did anyone solved this issue? Thanks
EDIT (Solution in Java):
RequestOptions requestOptions = RequestOptions.builder().setStripeAccount(retrieveKey("CONNECTED_ACCOUNT_ID")).build();
PaymentIntent paymentIntent = PaymentIntent.retrieve(paymentIntentID, requestOptions);
List<Charge> charges = paymentIntent.getCharges().getData();
for (Charge cg : charges) {
paymentMethodType = cg.getPaymentMethodDetails().getType();
}
If you're using Checkout, the returned session object will include the associated payment_intent ID, which can be used with Retrieve a PaymentIntent.
When retrieving the PaymentIntent you can optionally 'expand' the payment_method field, which will return the full pm_ object associated with the payment. This will include all details, including type field.
This will differ depending on your language/integration. Using Node.js:
stripe.paymentIntents.retrieve('pi_XXX', {
expand: ['payment_method'],
});

Stripe: Getting Credit Card's Last 4 Digits

I have upgraded the Stripe.net to the latest version which is 20.3.0 and now I don't seem to find the .Last4 for the credit card. I had the following method:
public void CreateLocalCustomer(Stripe.Customer stipeCustomer)
{
var newCustomer = new Data.Models.Customer
{
Email = stipeCustomer.Email,
StripeCustomerId = stipeCustomer.Id,
CardLast4 = stipeCustomer.Sources.Data[0].Card.Last4
};
_dbService.Add(newCustomer);
_dbService.Save();
}
But now the stipeCustomer.Sources.Data[0].Card.Last4 says 'IPaymentSource' does not contain a definition for 'Card'. Does anyone know how I can get the card details now? The flow is that I create the customer by passing the Stripe token to Stripe, then I get the above stripeCustomer. So I expect it to be somewhere in that object. But I can't find it. The release notes can be found here.
Thank you.
In the old world of Stripe, there only used to be one type of payment method you could attach to a Customer; specifically, Card-objects. You would create a Card-object by using Stripe.js/v2 or the Create Token API Endpoint to first create a Token-object and then attach that token to a Customer-object with the Create Card API Endpoint.
Once Stripe expanded to support a number of other payment methods though, Stripe built support for a new object type that encapsulated a number of payment methods (including credit cards) called Source-objects. A Source-object is created either by using Stripe.js/v3 or the Create Source API Endpoint. It can also be attached to a Customer-object in much the same way as the Card-objects mentioned above, except they retain their object type. They're still a Source. You use the Attach Source API Endpoint to do this (that is notably identical to the Create Card API Endpoint mentioned above).
What I'm getting at here, is there are now two different object types (or more) that you can expect to see returned in the sources-array (or Sources in .NET). All of these methods though inherit from the IPaymentSource-interface. So if you know you have a Card-object getting returned, you can simply cast the returned object to the Card-class.
Something like this should get you going:
CardLast4 = ((Card) stipeCustomer.Sources.Data[0]).Last4
You can see what I mean by inheritance by looking at this line in the Card-class file:
https://github.com/stripe/stripe-dotnet/blob/master/src/Stripe.net/Entities/Cards/Card.cs#L7
Good luck!
As of Stripe.net.21.4.1, this is what works:
var chargeService = new ChargeService();
var charge = chargeService.Get(id);
CardLast4 = ((Card)charge.Source).Last4;
It's getting hard not to panic when code breaks because of all the micro-changes Stripe makes.
So after debugging, it looks like the Data[0] needs to be cast as Card to get the card.
So it will be CardLast4 = ((Card)stipeCustomer.Sources.Data[0]).Last4.

DialogFlow conv.user.id Deprecated - any implications?

Similar to DialogFlow V2 user id? I am using the user ID from conv.user.id (dialogflow v2) to (anonymously) determine the user in my Dialogflow app. However, I get the log message:
conv.user.id is *DEPRECATED*: Use conv.user.storage to store data instead
Does this mean I will (soon) no longer have access to the user id? I understand I can store data in conv.user.storage, yet I need the id - not the storage.
Anyone thoughts on how to fail-safe this?
// Code snippet:
app.intent('Default Welcome Intent', conv => {
var userID = conv.user.id;
// do something
});
The anonymous user identity has been deprecated and will be officially removed starting 1 June 2019 (a year from now). So your code snippet will start failing then.
The fix depends on exactly how and why you're using the id, but for the most basic needs, you can do something like this:
Check to see if you've stored an id in the userStore. If you have - use this id.
If you haven't, generate an id (generating a UUID is a good method to do this), use this as your id, and store it in the userStore for future reference.
Code to do this might look something like this:
if ('userId' in conv.user.storage) {
userId = conv.user.storage.userId;
} else {
// generateUUID is your function to generate ids.
userId = generateUUID();
conv.user.storage.userId = userId
}
Alternately, you may wish to just plan to use Google Sign-In for the Assistant which will get you the Google UserID.
EDIT:
userId in condition should be quoted.

How to count number of activities in a getstream feed?

Does getstream provide a way to retrieve the number of activities within a feed? I have a notification feed setup. I can retrieve the activities using paginated get. However, I would like to display the number of items within the feed.
Unfortunately not, there is no API endpoint to retrieve the amount of activities within a feed.
At the moment there's no way to count activities directly. You can try
Use a custom feed and use reactions. So now you call count from reactions.
Other way is store in your app (cache/db/etc).
It worked for me:
signature = Stream::Signer.create_jwt_token('activities', '*', '<your_secret>', '*')
uri = URI("https://us-east-api.stream-io-api.com/api/v1.0/enrich/activities/?api_key=<api_key>&ids=<id1,id2,...>&withReactionCounts=true")
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req['Stream-Auth-Type'] = "jwt"
req['Authorization'] = signature
res = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => true) {|http|
http.request(req)
}
puts JSON.parse(res.body)
References:
Retrieve
reactions_read-feeds
activities
ruby client
Update 2022
You can only get the number of activities in groups within aggregated or notification feeds. Flat feeds are still not supported.
Source
The best solution is to store important numbers in the database which Stream provides.
Source

Un-canceling a Stripe subscription

Suppose a user wants to cancel their subscription, so I issue a command like this:
stripe_subscription.delete(at_period_end: true)
Later, though—before the period ends—the user changes their mind. Is there a call I can issue to undo the scheduled cancellation?
If not, what's the best way to implement this? My best guess looks like this:
new_subscription = stripe_customer.subscriptions.create(plan: stripe_subscription.plan.id, trial_end: stripe_subscription.current_period_end)
stripe_subscription.delete() # if permitted
self.stripe_subscription = new_subscription
save!
Is there something better I can do?
If the subscription is still active, you just have to update the current subscription and pass the plan id once again and it would resume the subscription.
In PHP you would do:
$customer = Stripe_Customer::retrieve("cus_XXX");
$subscription = $customer->subscriptions->retrieve("sub_YYY");
$subscription->plan = "myPlanId";
$subscription->save();
This is covered in one of Stripe's support article in more details here.
Not sure if the accepted answer is an old one, but for the latest version of Stripe you have to do this (in PHP):
$sub->cancel_at_period_end = false;
return $sub->save();
From the dashboard. Go to your Subscription details and click Edit Details top corner right. A modal untitled "Reactivate subscription" should pop saying
This subscription is set to cancel at the end of the period. You can
reactivate the subscription and it'll continue as usual.
Click Reactivate
EDIT
It seems that the actions now appear on mouse over the remaining days before cancellation:
Note that it wont show if the subscription is already canceled.
As per the above answer from Supersan, this solution also works for C# using the latest Stripe.net library 21.4.1
var items = new [] { new SubscriptionItemUpdateOption() { Id = i.Id, PlanId = i.Plan.Id } }.ToList();
var updateOptions = new SubscriptionUpdateOptions { Items = updatedItems, CancelAtPeriodEnd = false };
await subscriptionService.UpdateAsync(externalSubscriptionId, updateOptions);
Where I've just set the Id and Plan Id to whatever they were before. Not sure if these are necessary if you aren't using multiple plan subscriptions.

Resources