Reputation: 1207
I'd like to send the customer a Stripe pre-built invoice receipt email when or after their invoice is marked as "paid_out_of_band". There doesn't seem to be a way in the API to replicate the behaviour of the "Send Receipt" button for invoices via the Dashboard: https://stripe.com/docs/receipts#manually-send-receipts-from-the-dashboard
I know it is possible if I used the PaymentIntent which is generated by the Invoice, however this is only available when the invoice is finalised. In this use case the user can edit their order and return to checkout, I'd prefer that we're not creating multiple invoices and finalising them each time this happens. To resolve this I am using a separate PaymentIntent, updating it until the user clicks confirm, then generating the Invoice once the we get the payment_intent.succeeded
webhook. You can't link the Invoice and PaymentIntent up this way sadly so I simply cross reference them in the metadata for both objects.
I know I can send my own email with a link to the online receipt which exists on the Invoice but I would prefer to use the pre-built Stripe versions.
Upvotes: 5
Views: 1894
Reputation: 5234
With a headless browser framework, you can orchestrate a login followed by a call to https://dashboard.stripe.com/ajax/emails/resend_receipt
. Stripe Dashboard will show you the param names, which as charge
(id) and email_to
.
It would be nice if Stripe opened this feature up to API as you may want to exclude some clients from automatic receipt delivery based on your own criteria.
Until then, we only have workarounds.
Upvotes: 1
Reputation: 4194
I have the similar problem before, and I did handle it by retrieving the payment receipt email html that available in the "charge" event object, then send it as a html body for your email sender.
For example, in my case using django & djstripe:
import stripe
import requests
from typing import Union
from djstripe import webhooks
from django.core.mail import EmailMessage
stripe.api_key = "xxxx"
def get_stripe_payment_receipt_html(
invoice_or_payment_intent_data: dict,
) -> Union[str, None]:
"""
function to retrieve the html text of payment receipt from stripe.
:param `invoice_or_payment_intent_data` is dict of paid invoice or
payment intent data that has "charge" or "latest_charge" id.
:return html string or None
"""
if (
isinstance(invoice_or_payment_intent_data, dict)
and invoice_or_payment_intent_data
):
charge_id: Union[str, None] = invoice_or_payment_intent_data.get(
"charge"
) or invoice_or_payment_intent_data.get("latest_charge")
if not charge_id:
return None
try:
charge_data = stripe.Charge.retrieve(charge_id)
receipt_url: Union[str, None] = charge_data.get("receipt_url")
if receipt_url:
try:
response = requests.get(receipt_url, timeout=20)
if response.status_code == 200:
return response.text
except requests.exceptions.HTTPError:
...
except (
stripe.error.RateLimitError,
stripe.error.InvalidRequestError,
stripe.error.AuthenticationError,
stripe.error.APIConnectionError,
Exception,
):
...
return None
@webhooks.handler("invoice.payment_succeeded")
def invoice_payment_succeeded(event, **kwargs):
invoice_data: dict = event.data["object"]
...
html_message = get_stripe_payment_receipt_html(invoice_data)
if html_message is not None:
try:
message = EmailMessage(
subject="Receipt from Foobar"
body=html_message,
from_email=settings.EMAIL_HOST_USER,
to=[user.email],
bcc=[default_email],
reply_to=[default_email],
)
message.content_subtype = "html"
message.send()
except Exception as error:
...
else:
# using own payment receipt template
...
@webhooks.handler("payment_intent.succeeded")
def payment_intent_succeeded(event, **kwargs):
payment_intent_data: dict = event.data["object"]
...
html_message = get_stripe_payment_receipt_html(payment_intent_data)
...do the same as previous script
Upvotes: 3