const reader = await stripe.terminal.readers.processPaymentIntent(
'reader_id',
{ payment_intent:'payment_intent.id' }
);
I am integrating stripe terminal for collecting payment. I have created payment intent first and then I am processing that payment intent with processPaymentIntent API. I have read in stripe docs that after processing it changes status from 'requires_payment_method' to 'requires_capture' but in my case it is not changing status. Please guide me. Thanks in advance!
After processPaymentIntent you will need to wait for customers to insert their card to the reader. Have you observed that step is done successfully? There are 4 approaches to observe:
Listen to webhooks
Poll the Stripe API
Use the PaymentIntent
Use the reader object
Refer to Stripe Doc for more detail.
Related
I have an integration test connected to Stripe (test mode) and I would like to test the complete flow, i.e. creating payment-intent and handling the webhook of succeeded event. The first part is pretty straightward. Now for the second part, Obviously I can't do actual flow on the Element widget. So I tried to manually confirm the payment intent (as part of the test code) with the following call:
fun confirmPaymentIntent(pi: PaymentIntent): PaymentIntent {
val params = PaymentIntentConfirmParams.builder()
.addExpand("latest_charge")
.setPaymentMethod("pm_card_visa") // Don't know what's the correct value!
.setReturnUrl("https://example.com/return")
.build()
return pi.confirm(params)
}
And it works fine, I receive the "payment intent succeeded" event in the webhook. Now the problem is that the real payment flow would contain billing details. So I tried the following:
.setPaymentMethodData(
PaymentIntentConfirmParams.PaymentMethodData.builder()
.setBillingDetails(
BillingDetails.builder()
.setAddress(BillingDetails.Address.builder().setCountry("US").build())
.setName("My Customer")
.setEmail("customer#example.com")
.build()
)
.build()
)
But when I run the code, it's complaining about missing type in the payment method data. Type enum doesn't have card and I have no idea what is the correct value.
In my case, the application supports only cards and it doesn't care about the card details in any way (so anything works, like fake card, token, etc, as long as I get the payment intent event with the name and email info in the webhook.)
First, is there any better way to do this? Second, if not, then how can I manually confirm a payment intent in the test to be able to verify webhook call? Thanks.
You can trigger the payment_intent.succeeded event directly via Stripe CLI. If that still doesn't give you the information to test, you would want to build an end-to-end frontend confirmation flow using PaymentElement. It's not that complicated.
Using Stripe/iOS, the user of the app can pay by credit card or by Apple Pay.
I want, from the app (not the server), to request an email receipt when payment is successful.
For Credit Card payment I do the following:
let paymentIntentParams = STPPaymentIntentParams(clientSecret: <paymentIntentClientSecret>)
paymentIntentParams.paymentMethodParams = paymentMethodParams
if let receiptEmail = self.receiptEmail {
paymentIntentParams.receiptEmail = <email address>
}
let paymentHandler = STPPaymentHandler.shared()
paymentHandler.confirmPayment(withParams: paymentIntentParams,
authenticationContext: authenticationContext) {
…
}
However for Apple Pay payment I don’t know which property to set. In the app, I implement the STPApplePayContextDelegate protocol.
Question: For Apple Pay payment, what and where I need to set the email-address for the receipt? Can you please provide a code snippet?
Thanks
After discussion with Stripe support, it seems that using STPApplePayContextDelegate there is no way to set the receiptEmail property in the payment intent.
The best approach is to change the server and set the receiptEmail at
the server
If you still want to make the change at the app, the workaround is to use the REST API to update the payment intent.
Below is the reply from Stripe support:
The STPApplePayContext does not support this directly -- it needs to be set on the payment intent. The iOS flow for card payments is described in [0] and support receiptEmail in the STPPaymentIntentParams [1], but the Apple Pay flow is different. If not set when you create the payment intent, you would then want to make a call to your server to update the payment intent [2] in the payment flow where you call the completion. Alternately, confirm the payment intent server-side after collecting the Apple Pay payment method client-side [3].
[0] https://stripe.com/docs/payments/accept-a-payment?platform=ios&ui=custom#ios-submit-payment
[1] https://stripe.dev/stripe-ios/docs/Classes/STPPaymentIntentParams.html#/c:#M#Stripe#objc(cs)STPPaymentIntentParams(py)receiptEmail
[2] https://stripe.com/docs/api/payment_intents/update#update_payment_intent-receipt_email
[3] https://stripe.com/docs/apple-pay?platform=ios#client-side
I am writing tests for how the billing system reacts to various events in Stripe. In our backend tests there is a mode to run billing tests so that it talks to Stripe API instead of using fixtures. And it saves responses from Stripe automatically as fixtures. This means you only need to run tests in fixture generation mode when there are changes made to the Stripe API or billing system.
The tricky part ofcourse is to see how the system reacts to webhook events from Stripe. The workaround I found is to use the stripe events API endpoint to fetch the recent events and post it to the webhook endpoint. You can make this work for pretty much all the important events. For example attaching a valid a PaymentMethod to a PaymentIntent will result in a payment_intent.succeeded event. And you can get that event using stripe.Event.list and send the event to the webhook the billing system to emulate the event.
The event I am having a toruble generating is the checkout.session.completed event. Since it looks like you can generate the event only after going through Stripe checkout which is not possible in backend. Ofocurse, you can create a fake event like this
[checkout_setup_intent] = stripe.SetupIntent.list(limit=1)
stripe_setup_intent = stripe.SetupIntent.create(
payment_method=payment_method.id,
confirm=True,
payment_method_types=checkout_setup_intent.payment_method_types,
customer=checkout_setup_intent.customer,
metadata=checkout_setup_intent.metadata,
usage=checkout_setup_intent.usage,
)
[stripe_session] = stripe.checkout.Session.list(limit=1)
stripe_session_dict = stripe_session.to_dict_recursive()
stripe_session_dict["setup_intent"] = stripe_setup_intent.id
event_payload = {
"object": "event",
"data": {"object": stripe_session_dict},
"type": "checkout.session.completed",
}
But that is less than ideal. Is there a way to trigger the checkout.session.completed event with real data and without the need of a web ui?
My solution was to use e2e testing (with cypress) to complete payment, and call it from my integration testing code.
This takes around 10 seconds to complete.
NUnit test:
var paymentUrl = "https://checkout.stripe.com/pay/cs_test_a1nqdPnsxtq.......";
Process process = new Process();
process.StartInfo.WorkingDirectory = #"C:\PathToCypress";
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = $"/c npx cypress run --env url={paymentUrl}";
process.StartInfo.UseShellExecute = true;
process.Start();
process.WaitForExit();
Cypress script:
describe('Stripe Billing', () => {
it('Completes a checkout session', () => {
cy.visit(Cypress.env('url'));
// Enter billing details
cy.get('#cardNumber').type('4242424242424242');
cy.get('#cardExpiry').type('3333');
cy.get('#cardCvc').type('3333');
cy.get('#billingName').type('TestName');
cy.get('.SubmitButton').click();
// Wait for payment to succeed
cy.server().route('GET', 'https://api.stripe.com/v1/checkout/sessions/completed_webhook_delivered/*').as('completed'); // define request
cy.wait('#completed', { timeout: 60000 });
})
})
You can with the Stripe CLI:
stripe trigger checkout.sessions.completed
The stripe documentation says when using payment intent using automatic confirmation you should Asynchronously fulfill the customer’s order using webhooks.
If i'm offering a service e.g. ability to download a file once purchased then why do I need to monitor for the payment_intent.succeeded webhook?
If payment succeeded in the following handleCardPayment function then is there still a possibility for the charge to fail? Why shouldn't I allow the user to download the file straight away if the payment has succeeded?
var cardholderName = document.getElementById('cardholder-name');
var cardButton = document.getElementById('card-button');
var clientSecret = cardButton.dataset.secret;
cardButton.addEventListener('click', function(ev) {
stripe.handleCardPayment(
clientSecret, cardElement, {
payment_method_data: {
billing_details: {name: cardholderName.value}
}
}
).then(function(result) {
if (result.error) {
// Display error.message in your UI.
} else {
// The payment has succeeded. Display a success message.
}
});
});
Maybe I've not understood how the handleCardPayment works. Any help appreciated.
When using handleCardPayment, the issue is not so much that the payment might fail, it's that it might succeed but your code doesn't know about it.
handleCardPayment kicks off several asynchronous steps — showing the user a dialog to authenticate a payment with their bank, processing the actual charge against their card, and closing the dialog. It's only after all that completes does the Promise resolve and your function that receives result executes.
Consider the case where:
the customer clicks Pay
handleCardPayment is called
the customer sees a dialog from their bank to authenticate the
payment
they do that, and they consider that their payment is now complete,
and they close their browser immediately.
In this case, your code will never execute, but Stripe still processed the charge. So you don't know that the payment happened and you can't fulfil the order.
That's why it's important to use webhooks, so you get notified asynchronously when the payment completed, even if the user closed their browser mid-process and your code after handleCardPayment never got a chance to run. Alternatively you can use the manual confirmation flow, where the steps are split up and the actual charge isn't processed until your server makes a separate API call.
I'm using Create PayPal SDK to make a transaction using paypal and redirecting the user to paypal.
I'm using the same code as per suggested in above link, but i want to send invoice number with create paypal to be shown under transaction detail. but i am not able to find how can i send a invoice number to paypal.
Please guide me if there is any object in which i can sent the invoice number to Create PayPal SDK OR any other method through which i can sent invoice number to PayPal.
Note: this project is in sailsjs.
Thanks
Please check this: https://github.com/paypal/PayPal-node-SDK/blob/master/samples/invoice/send.js
var invoiceId = "INV2-GLJ8-9FA2-26BB-GHLU";
paypal.invoice.send(invoiceId, function (error, rv) {
if (error) {
console.log(error.response);
throw error;
} else {
console.log("Send Invoice Response");
console.log(rv);
}
});
Please look at the complete invoice example here, there is everything you need: https://github.com/paypal/PayPal-node-SDK/tree/master/samples/invoice
As per documentation you can handle your custom IDs:
For exploring additional payment capabilites, such as handling
discounts, insurance, soft_descriptor and invoice_number, have a look
at this example. These bring REST payment functionality closer to
parity with older Merchant APIs. https://github.com/paypal/PayPal-node-SDK