Thomas Nadin
Thomas Nadin

Reputation: 1207

How to send receipt for invoice via Stripe API

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

Answers (2)

Half_Duplex
Half_Duplex

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

binpy
binpy

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

Related Questions