Reputation: 1601
I try to use the new Stripe's PaymentIntent system to be ready when SCA will be launched in EU.
I only use one-time payment.
I succeed to make the payment with the PaymentIntent following Stripe's documentation. But I'm unable to create an invoice for every payment (I must have one according to the law), and I tried a lot of things.
But first, I think I need to show my code to introduce the troubles I have.
In my view, I create a Stripe Session :
public_token = settings.STRIPE_PUBLIC_KEY
stripe.api_key = settings.STRIPE_PRIVATE_KEY
stripe_sesssion = stripe.checkout.Session.create(
payment_method_types=['card'],
line_items=[{
'name':'My Product',
'description': description,
'amount': amount,
'currency': 'eur',
'quantity': 1,
}],
customer=customer_id,
success_url=f'{settings.SITE_URL}/ok.html',
cancel_url=f'{settings.SITE_URL}/payment_error.html',
)
Then, the user click on the "Purchase" button on my web page and is redirected to the Stripe's Checkout page.
After the user filled his payment card informations, Stripe call my Webhook (according to the checkout.session.completed event triggered).
Here's my webhook function code :
@csrf_exempt
def webhook_payment_demande(request):
payload = request.body
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
event = None
if settings.DEBUG is False:
endpoint_secret = "whsec_xxx"
else:
endpoint_secret = "whsec_xxx"
try:
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
except ValueError as e:
# Invalid payload
return HttpResponse(status=400)
except stripe.error.SignatureVerificationError as e:
# Invalid signature
return HttpResponse(status=400)
# Handle the event
if event['type'] == 'checkout.session.completed':
stripe_session = event['data']['object']
invoice_item = stripe.InvoiceItem.create(
customer=customer_id,
amount=str(amount),
currency="eur",
description=description
)
invoice = stripe.Invoice.create(
customer=customer_id,
)
invoice_payment = stripe.Invoice.pay(
invoice,
source=card
)
[...] Deliver product by e-mail and stuff [...]
I'm reading the documentation for days and I've not found a good tutorial to make a one-time Payment with SCA compatibility and having a bill after that.
Is a nice person has already fixed his/her Stripe payment API system for SCA compliance and have found a way to deal with this ?
A lot of thanks for your help ! :)
Upvotes: 0
Views: 3185
Reputation: 1282
Posting this as requested. Using .NET and React.js. Steps:
On load of the payment page, I call stripe to create an Intent from my API
var response = await _setupIntentService.CreateAsync(new SetupIntentCreateOptions
{
PaymentMethodTypes = new List<string> { "card" },
Usage = "off_session", // Allows card to be used later one
});
return response.ClientSecret;
Then using stripe elements, I render the card details form (self explanatory on the stripe docs website). On submission of this form, call stripe with the intent to create a payment method (React):
this.props.stripe.handleCardSetup(intent)
.then((stripeResponse) => {
submitSubscription(stripeResponse.setupIntent.payment_method);
})
submitSubscription calls my API.
If the customer exists, I detach the existing payment method
_paymentMethodService.ListAsync(new PaymentMethodListOptions { Limit = 1, CustomerId = customerId, Type = "card" });
if (paymentMethods.Any())
{
await _paymentMethodService.DetachAsync(paymentMethods.First().Id, new PaymentMethodDetachOptions());
}
And attach the new payment method, also setting the default payment for the customer
var options = new PaymentMethodAttachOptions { CustomerId = customerId };
await _paymentMethodService.AttachAsync(paymentMethodId, options);
await _customerService.UpdateAsync(customer.Id, new CustomerUpdateOptions
{
InvoiceSettings = new CustomerInvoiceSettingsOptions { DefaultPaymentMethodId = paymentMethodId }
});
If the customer doesn't exist, create one with the payment method id
_customerService.CreateAsync(new CustomerCreateOptions
{
Email = email,
PaymentMethodId = paymentMethodId,
InvoiceSettings = new CustomerInvoiceSettingsOptions { DefaultPaymentMethodId = paymentMethodId }
});
I'm using plans and subscriptions which are well documented by Stripe but my main issue was I was using Source and payment methods together. Source was the old way if you are taking off session
payments.
Hope that helps.
Upvotes: 0
Reputation: 25552
Your code is creating one-time charges via Checkout. What you are looking for is the email receipt feature as documented here https://stripe.com/docs/receipts
This lets you email your customer after a successful charge on your account which should act as an Invoice. You can also link to this email receipt directly by looking at the Charge's receipt_url
property: https://stripe.com/docs/api/charges/object#charge_object-receipt_url
Upvotes: 0