Get Stripe to charge existing card on subscription change - c#

I'm offering my customers monthly subscriptions. When they sign up to a paid subscription plan for the first time they are shown a PaymentElement to capture their credit card details. Once this is complete the customer has a new payment method stored on Stripe. This works fine.
However, when the customer wants to upgrade to a higher subscription plan, Stripe creates a prorated payment on the customer, but for some reason, doesn't actually charge the customer's existing payment method. The payment on Stripe is sitting at Incomplete with the message The customer hasn't attempted to pay this invoice yet.
My question is, why doesn't Stripe just charge the customer using the already stored payment method? Why is it waiting for the customer to pay?
This is how I'm initiating the upgrade (This is also the same code I use to move to the customer to a paid subscription, capturing their card details):
var service = new SubscriptionService();
var subscription = service.Get(subscriptionId);
var paymentSettings = new SubscriptionPaymentSettingsOptions
{
SaveDefaultPaymentMethod = "on_subscription"
};
var options = new SubscriptionUpdateOptions
{
CancelAtPeriodEnd = false,
ProrationBehavior = "always_invoice",
Items = new List<SubscriptionItemOptions>
{
new SubscriptionItemOptions
{
Id = subscription.Items.Data[0].Id,
Price = planPriceCombo.Item2
}
},
PaymentSettings = paymentSettings,
PaymentBehavior = "default_incomplete"
};
options.AddExpand("latest_invoice.payment_intent");
var updatedSubscription = service.Update(subscriptionId, options);
Have I configured this subscription update incorrectly? How would I go about getting Stripe to just automatically charge the payment method already attached to the customer without waiting?

Your code is passing PaymentBehavior = "default_incomplete" which indicates to Stripe that you don't want them to attempt to pay the Invoice by confirming its underlying PaymentIntent. If you look at updatedSubscription.LatestInvoice.PaymentIntent.Status it likely is in requires_confirmation to reflect this. In that case, you would use the PaymentIntent's ClientSecret value to confirm the PaymentIntent client-side, for example in case 3DS is needed.
Since you want Stripe to automatically attempt payment of the Invoice on creation, what you need to do is switch to PaymentBehavior = "allow_incomplete" instead. This means Stripe will attempt a payment synchronously but if it fails or requires a customer action (such as doing 3DS) it won't error and still go through with the update. This will then let you attempt to confirm the PaymentIntent client-side if needed.

Related

GlobalPay challengeRequestIndicator not showing on Hpp Response

I have a web app that processes payments via globalpay using their HPP solution. It works and is live at the moment but I have tried to implement their save card functionality.
The issue is that with some banks we get and error Invalid Transaction and been advised that it is due to the challenge request indicator not being passed. I have tried adding this in using the HostedPaymentData entity but does not show in the hpp response. there is documentation on builders with the challenege request indicator as well below but not sure how to implement this with my .net request.
They provided me some docs on builders below that has withChallengeRequestIndicator but not sure how to add this to my .net request.
https://github.com/globalpayments/dotnet-sdk/blob/0916facfc690aa4379bbe60d80f08eb40b0e4da2/src/GlobalPayments.Api/Builders/Secure3dBuilder.cs#L163
hostedPaymentData = new HostedPaymentData
{
OfferToSaveCard = true, // display the save card tick box
CustomerExists = true, // new customer
CustomerKey = custKey,
CustomerEmail = userCustomerEmail,
CustomerPhoneMobile = userCustomerPhoneMobile,
AddressesMatch = false,
ChallengeRequestIndicator = ChallengeRequestIndicator.NO_PREFERENCE,
};
Most payments will still process ok but some banks seem to throw and Invalid transaction 101 Error, Global pay advised its to do with this challenge request not being present in the response.
Any help

Manage a long-running operation in MS Teams Bot

I am using the following sample / article to Manage a Long-running operation in MS Teams Bot.
https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-howto-long-operations-guidance?view=azure-bot-service-4.0
In step 5, a DirectLineClient is being created and an Event Activity is sent to Bot using PostActivityAsync.
var responseActivity = new Activity("event");
responseActivity.Value = originalActivity;
responseActivity.Name = "LongOperationResponse";
responseActivity.From = new ChannelAccount("GenerateReport", "AzureFunction");
var directLineSecret = Environment.GetEnvironmentVariable("DirectLineSecret");
using(DirectLineClient client = new DirectLineClient(directLineSecret))
{
var conversation = await client.Conversations.StartConversationAsync();
await client.Conversations.PostActivityAsync(conversation.ConversationId, responseActivity);
}
However, I need the above sample to work for MS Teams Bot and not the DirectLineClient.
I used Microsoft.Bot.Connector.ConnectorClient but StartconversationAsync and PostActivityAsync methods are not available.
I tried the methods available in Microsoft.Bot.Connector.ConnectorClient
connectorClient.Conversations.CreateConversationAsync(conversationparameters)
connectorClient.ConversationsCreateDirectConversationAsync(botAccount, userAccount, (Activity)newActivity);
connectorClient.Conversations.SendToConversationAsync(conversationid, (Activity)newActivity);
But all the methods failed with Bad Requestwith the error as seen in the Response:
{"error":{"code":"BadArgument","message":"Unknown activity type"}}
The newActivity is created as below:
var messagnewActivity = new Activity("event");
newActivity.Value = originalActivity;
newActivity.From = new ChannelAccount("GenerateReport", "AzureFunction");
newActivity.Type = "event";
newActivity.Conversation = new ConversationAccount { Id = originalActivity.Conversation.Id };
newActivity.ChannelId = originalActivity.ChannelId;
Can someone please suggest how do I pass the Activity (Event Activity type) to MS Teams Bot.
Thanks
Gagan
I'm not really familiar with Direct Line, but I think it's effectively an -alternative- type of bot to Teams, so if you're trying to do this inside Teams, it explains the issue. In principle, the basic idea is quite simple though:
you store state somehow (e.g. in memory or in a database) to indicate that the long running operation is in progress for the user
when the long-running process is complete, your code (which could live OUTSIDE your bot, e.g. in an Azure Function) can send the user a message AS IF IT WAS the bot - this is called Pro-Active Messaging and you can read more about it at https://learn.microsoft.com/en-us/graph/teams-proactive-messaging.
This is to inform you that I was facing the same issue sometime before then I found a tweak in the code while debugging. when it calls twice recursively then the Activity Id is the same as the previous one. you can check if the activity id is the same then return the request else go with it.

Using Stripe to process payments on server

I have a vue.js project as a UI which sends requests to my .NET Core API app to process typical CRUD requests.
I have been following the documentation on https://stripe.com/docs/payments/accept-a-payment-synchronously
I've set up the payment method creation on the vue.js project which creates an identifier for the users card details, which is then sent to the API to be processed/completed:
[HttpPost("buy")]
public async Task<IActionResult> Buy(PaymentRequest request)
{
StripeConfiguration.ApiKey = _stripeSettings.Key;
var options = new PaymentIntentCreateOptions
{
PaymentMethod = request.paymentMethod,
Amount = 300,
Currency = "gbp",
ConfirmationMethod = "manual",
Confirm = true
};
var intent = await _paymentIntentService.CreateAsync(options);
return Ok(intent.ClientSecret);
}
I am then able to view this successful transaction on my Stripe dashboard.
I can't find anything useful online, but is there a way to process all of this in the backend without my frontend knowing anything about stripe? The reason I ask, is because I would like some sort of seperation of concerns as if I was to change the integration for accepting payments in future I wouldn't need to update the frontend.

RestAPISDK .Net Execute Payment

I'm trying to implement Paypal in an ASP.Net website. I've installed the RestAPISDK and I've been following this guide by Paypal (https://devtools-paypal.com/guide/pay_paypal/dotnet) as well as looking at the references located here (https://developer.paypal.com/webapps/developer/docs/api/#execute-an-approved-paypal-payment)
So far it's going well, but upon returning from Paypal's website, I'm not able to execute the payment as per their documentation.
The Guide says to use the following code
Dictionary<string, string> sdkConfig = new Dictionary<string, string>();
sdkConfig.Add("mode", "sandbox");
string accessToken = "TOKEN";
APIContext apiContext = new APIContext(accessToken);
apiContext.Config = sdkConfig;
Payment payment = new Payment("PAYMENT ID");
PaymentExecution pymntExecution = new PaymentExecution();
pymntExecution.payer_id = ("DYRNAJP829GTN");
Payment executedPayment = pymnt.Execute(apiContext,pymntExecution);
But Payment has no constructor that take in the Payment ID.
The Rest API Reference says to use the following method
Payment payment = Payment.Get(accessToken, "Payment ID");
However, Payment.Get is depreciated. If I use it anyway I just get an Exception saying the server responded with a 404.
What are we supposed to use instead? I can't find any up to date documentation to point me in the right direction.
I'm thinking I may have to use HttpClient to send the Request myself but surely I shouldn't have to do that.
I agree, the C# samples do not work and produce the same 404 exception when you try to Execute a payment with your own sandbox store.
What you need to do is:
Payment payment = Payment.Get(context, paymentID);
where context is your apiContext and paymentID is the id passed back in by the return url from PayPal.
you then need:
var paymentExecution = new PaymentExecution
{
payer_id = payerId
};
finally you can then call:
payment.Execute(context, paymentExecution);
this returns a payment object, which should have the 'state' of approved...
It is the PaymentHistory retrieval method that is deprecated in favor of the Payment.List() method. To retrieve a single payment, you still use the Payment.Get method.
Are you sure you are passing in a valid payment id for the second parameter here? A 404 (Not Found) error is thrown when a payment with the passed in ID does not exist.

User Master Account to send SMS on behalf of a Sub Account

I'm developing a feature for our product that will allow users to send SMS messages via Twilio and we handle all of the account issues. We have our Master Account and all of our customers will be sub accounts under us.
In an effort to not have to keep track of 1000+ auth tokens, we decided to use our Master Account credentials to send the SMS message however we still want it to roll up under the sub account. According to Twilio, this shouldn't be an issue.
My problem is that there is very little (that I've found) documentation for the c# library they provide. I'm not sure if what I've done is the correct way to accomplish what I described above and since I'm on a trial account until the project is finished and can be rolled out to production I have no way of testing.
var twilio = new TwilioRestClient("Master SID", "Master Auth Token");
var response = twilio.SendSmsMessage(sender, recipient.ConvertToE164Format(), message, null, "Subaccount SID");
The comment on this overload isn't really clear on if passing the subaccounts SID here will send the message as if I had logged into their account and sent it.
// applicationSid:
// Twilio will POST SmsSid as well as SmsStatus=sent or SmsStatus=failed to
// the URL in the SmsStatusCallback property of this Application. If the StatusCallback
// parameter above is also passed, the Application's SmsStatusCallback parameter
// will take precedence.
The callback url will be the same across all accounts so I don't need/care about that value.
Short Version:
If I log in with my Master Account details but pass the subaccount SID in the SendSmsMessage() method, which account does the message come from?
Twilio support finally got back to me and confirmed my fears that this wouldn't work. I do have to pull the subaccount information down and reinstantiate the twilioRestClient with the new credentials which I was hoping I could get away with not doing. Just a few extra lines.
var twilio = new TwilioRestClient("Master SID", "Master Auth Token");
var subAccount = twilio.GetAccount("SubAccount SID");
var subAccountClient = new TwilioRestClient(subAccount.Sid, subAccount.AuthToken);
var response = subAccountClient.SendSmsMessage(sender, recipient.ConvertToE164Format(), message);
return response.Sid;

Categories

Resources