GlobalPay challengeRequestIndicator not showing on Hpp Response - c#

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

Related

Get Stripe to charge existing card on subscription change

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.

Amazon Pay SDK CompleteCheckoutSession Error

I'm integrating Amazon pay with my website, using the v2 c# SDK from amazon (MVC App), in the sandbox. Setup is all good, I created the keys, return urls, etc.
In my checkout process, I create the CheckoutSession, which is successful. I click on the Amazon Pay button, log in using my test buyer account, and "pay" for the item using their valid test credit card.
Amazon redirects to my return URL with the checkout session id as expected.
When I try to CompleteCheckoutSession, the result is an error back from the Amazon API
error: InvalidCheckoutSessionStatus
message: You tried to call an operation on a Checkout Session that is in a state where that operation is not allowed
I put in a test line of code to retrieve the CheckoutSession to look at it before I try to complete it, and it shows that the current status is "Open", which is the correct status when trying to complete it, so I'm at a loss at why the checkout session status is invalid.
EDIT:
Note I'm using this flow for my transaction, so there is no "review" of the transaction. Buyer chooses his items on my site.
https://amazonpaycheckoutintegrationguide.s3.amazonaws.com/amazon-pay-apb-checkout/additional-payment-button-overview.html
Also note, I'm creating the payload dynamically according to this:
https://amazonpaycheckoutintegrationguide.s3.amazonaws.com/amazon-pay-checkout/amazon-pay-script.html#render-button-using-a-checkout-session-object
So when the amazonpay button is clicked, it calls a method on my site which builds the payload which begins the CheckoutSession. I then have the Amazon Session ID in my cache which I save it, and save the total. The payload is returned to the Amazon pay script which then takes me to the Amazon Site. I choose the payment type and click "continue to checkout", which sends me back to my site with the SessionId to do the "complete" step.
My request to CompleteCheckoutSession(sessionId)
{"chargeAmount":{"amount":99,"currencyCode":"USD"}}
result.RawResponse from the client.CompleteCheckoutSession(sessionId) method:
{
"reasonCode":"InvalidCheckoutSessionStatus",
"message":"You tried to call an operation on a Checkout Session that is in a state where that operation is not allowed"
}
EDIT SAMPLE CODE:
I created a brand new test MVC app with basic functionality:
public ActionResult Index()
{
var client = InitiateClient(); //hidden for security
// prepare the request
var request = new CreateCheckoutSessionRequest
(
checkoutReviewReturnUrl: "http://localhost:44300/home/completecheckout",
storeId: "amzn1.application-oa2-client.mystoreid"
);
request.PaymentDetails.PaymentIntent = Amazon.Pay.API.WebStore.Types.PaymentIntent.AuthorizeWithCapture;
request.PaymentDetails.ChargeAmount.Amount = 99;
request.PaymentDetails.ChargeAmount.CurrencyCode = Currency.USD;
// generate the signature and payload string that is passed back to the frontend
ViewBag.Signature = client.GenerateButtonSignature(request);
ViewBag.Payload = request.ToJson();
return View();
}
In the Index.cshtml file:
<div id="AmazonPayButton"></div>
<script src="https://static-na.payments-amazon.com/checkout.js"></script>
<script type="text/javascript" charset="utf-8">
amazon.Pay.renderButton('#AmazonPayButton', {
merchantId: 'mymerchantid',
ledgerCurrency: 'USD',
sandbox: true,
checkoutLanguage: 'en_US',
productType: 'PayOnly',
placement: 'Checkout',
buttonColor: 'Gold',
createCheckoutSessionConfig: {
payloadJSON: '#Html.Raw(ViewBag.Payload)', // string generated in step 2
signature: '#Html.Raw(ViewBag.Signature)', // signature generated in step 3
publicKeyId: 'AGPTYXGL5VH6PSYLJUSHTKW6'
}
});
</script>
And finally, the completecheckout code, which is unsuccessful:
public ActionResult CompleteCheckout(string amazonCheckoutSessionId)
{
var client = InitiateClient(); //hidden for security
var request = new CompleteCheckoutSessionRequest(99.00M, Currency.USD);
// send the request
var result = client.CompleteCheckoutSession(amazonCheckoutSessionId, request);
// check if API call was successful
if (!result.Success)
{
throw new Exception("API Call unsuccessful");
}
return View();
}
NOTE: certain keys obfuscated, but actual keys are in the sample code.
Manually creating the CheckoutSession doesn't work with the "no review page" flow that you are following. If you want to integrate this flow, you'll have to let Amazon Pay create the CheckoutSession for you using the createCheckoutSessionConfig parameter in the button code, see here: https://amazonpaycheckoutintegrationguide.s3.amazonaws.com/amazon-pay-apb-checkout/add-the-amazon-pay-button.html#4-render-the-button
EDIT:
The code sample below shows how to construct the payload and signature for the 'no order review' payment flow. Please note the CheckoutMode parameter, that instructs Amazon Pay to immediately process the payment, and the checkoutResultReturnUrl, that defines the URL where the buyer is sent to for completing the checkout. When the user arrives at that URL, you will have to call Complete CheckoutSession, which should now succeed.
public ActionResult Index()
{
var client = InitiateClient(); //hidden for security
// prepare the request
var request = new CreateCheckoutSessionRequest
(
checkoutReviewReturnUrl: null,
storeId: "amzn1.application-oa2-client.mystoreid"
);
// instructs Amazon Pay to immediately process the payment
request.WebCheckoutDetails.CheckoutMode = CheckoutMode.ProcessOrder;
request.WebCheckoutDetails.CheckoutResultReturnUrl = "http://localhost:44300/home/completecheckout";
// payment details
request.PaymentDetails.PaymentIntent = Amazon.Pay.API.WebStore.Types.PaymentIntent.AuthorizeWithCapture;
request.PaymentDetails.ChargeAmount.Amount = 99;
request.PaymentDetails.ChargeAmount.CurrencyCode = Currency.USD;
// generate the signature and payload string that is passed back to the frontend
ViewBag.Signature = client.GenerateButtonSignature(request);
ViewBag.Payload = request.ToJson();
return View();
}
I had a similar issue and it takes me a very long time to figure it out. This is what happened to me.
I was not intent to create production code. I just want to create a test page with only Amazon Pay button. I used several node js script to getCheckoutSession/updateCheckoutSession. However, when I tried completeCheckoutSession, I got "InvalidCheckoutSessionStatus".
In the end, I found, after I setup all the required parameter and remove all constraint, the updateCheckoutSession gives me a "amazonPayRedirectUrl" in API return. That URL is really important. You need to go that URL in order to complete the review...
This is from Amazon official website:
"Once there are no constraints, the response will return a unique
amazonPayRedirectUrl. Redirect the buyer to that URL to complete
checkout."
The other way to solve this issue is mentioned by "Daniel Lemke". In that way, shoppers don't need to confirm the session. However, you need to make sure to provide all useful information in webCheckoutDetails (paymentDetails, addressDetails). If you only give checkoutMode, you will get "MissingParameterValue".
This is from Amazon official website:
"paymentDetails is required when using 'ProcessOrder'. addressDetails
is also required if you use 'ProcessOrder' with productType set to
'PayAndShip'"

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.

Azure: getting invoice data with the BillingManagementClient class

The last line of the following code results in an "Operation returned an invalid status code 'BadRequest'" exception and I don't understand why:
Given the following code :
var tenantDomain = ConfigurationManager.AppSettings["TenantDomain"];
var clientId = ConfigurationManager.AppSettings["ClientID"];
var secret = ConfigurationManager.AppSettings["ClientSecret"];
var subscriptionId = ConfigurationManager.AppSettings["SubscriptionID"];
var serviceCreds = await ApplicationTokenProvider.LoginSilentAsync(tenantDomain, clientId, secret);
var bmc = new BillingManagementClient(serviceCreds);
bmc.SubscriptionId = subscriptionId;
List<Invoice> allInvoices = bmc.Invoices.List().ToList();
Suggestions anyone ? Should I specify a date period explicitly ? How?
Suggestions anyone ? Should I specify a date period explicitly ? How?
If we want to access Billing we need to assign the Billing Reader role to someone that needs access to the subscription billing. We could get the detail steps for the azure official tutorials. I also test the code you mentioned, there is no issue with code, if it is supported. The following is the snippet from the official tutorials.
The Billing Reader feature is in preview, and does not yet support enterprise (EA) subscriptions or non-global clouds.
Please have a try to login Azure Portal to check whether have access to Access to invoice. If you see the Access to invoice is disabled, it seems that the subscription type is not supported.
If you still have further questions, could contact support to get your issue resolved quickly.

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